
    soj^S              !       b   d dl Z d dlZd dlZd dlmZ d dlmZ d dlmZ d dl	m
Z
 d dlZd dlmZ d dlmZ d dlmZ d dlmZ d dlmZ d d	lmZ d d
lmZ d dlmZ d dlmZ d dl m!Z! d dl"m#Z# d dl$m%Z% d dl&m'Z' d dl(m)Z) d dl*m+Z+ d dl,m-Z- d dl.m/Z/ d dl0m1Z1 d dl2m3Z3 d dl4m5Z5 d dl6m7Z7 d dl8m9Z9 d dl:m;Z;m<Z<m=Z= d dl>m?Z@ d dlAmBZB d dlCmDZDmEZEm?Z?mFZF d dlGmHZH d dlImJZJ d d lKmLZLmMZM d d!lNmOZO d d"lPmQZQmRZRmSZS d#e
jT        d$dfd%ZU	 	 	 	 	 	 	 	 	 	 	 	 	 	 dMd(ed)eVd#e
jT        d*ed+eWd,eVd-eWd.eWd/eWd0eWd1e3d2eVd3eWd4ed5eWd$df d6ZXd)eYd(ed$eVfd7ZZ	 	 	 	 	 	 	 	 dNd*ed#e
jT        d(ed8eYeVz  d9eVd:eWd;e9d<e[e)         d=e\d>eWd?eWd@eWd$eWfdAZ]dBe^d$eVfdCZ_d$e j         fdDZ`d$eYfdEZad$e j         fdFZbdGe d$eWfdHZcdIedJedKe^d$e^fdLZddS )O    N)ceil)Case)Update)ContextTypes)
BountyGift)
BountyLoan)Crew)CrewMemberChestContribution)DavyBackFight)IncomeTaxEvent)User)BossType)BountyGiftStatus)BountyLoanStatus)get_first_new_world)Screen)DevilFruitAbilityType)IncomeTaxBracket)IncomeTaxBreakdown)IncomeTaxContributionType)IncomeTaxEventType)CommonChatException)BellyValidationException)Keyboard)get_next_runget_previous_runget_remaining_duration)add_contribution)get_ability_value)get_tax_amountget_tax_deductionsr   user_has_complete_tax_deduction)reset_location)"full_message_or_media_send_or_edit)get_boss_typeuser_is_boss)subtract_percentage_from_value)get_unit_value_from_stringobject_to_json_stringget_belly_formattedcontextreturnc                   K   ddl m} ddlm} ddlm}  |              ||            d{V  t          j        t          j        t          j	        z   d          
                                 t          j        dz  t                      j        k    t                      j        ft          j        dz  t          j                                        k     dfg}t!          d|t          j        dz            }t          j        |          
                                 t#                       t          j        d	
          
                                 t%          j                                        t$          j        t,          j        k              
                                 t1          j                                        t0          j                            t5          j                                        
                                 t          j        d          
                                 t          j        d          
                                 t9          j                    
                                 t:          j        t          j                                        k    t          j                                        fg}t!          d|t:          j                  }t;          j        ||d          
                                 tA          j!                                        t@          j"        t          j!        t          j"                                      t          j#        t@          j$        k              k              }tA          j                                        t@          j#        %                    d |D                                 
                                 t;          j&                     t;          j        d	          
                                 | j'        (                     ||                      dS )z;
    Resets the bounty for all users
    :return: None
    r   )force_end_all_active)'remove_all_bets_from_active_predictions)disband_inactive_crewsN)bountypending_bounty   )r1   T)can_create_crew)bounty_gift_tax)total_gained_bounty)chest_amountfrom_reset_chest_amounttotal_gained_chest_amountc                     g | ]	}|j         
S  )id).0contributions     "/app/src/service/bounty_service.py
<listcomp>z reset_bounty.<locals>.<listcomp>   s    III\III    )can_promote_captain))src.service.game_servicer.   src.service.prediction_servicer/   src.service.crew_servicer0   r   updater1   r2   executer   required_bountyEnvDAILY_REWARD_BONUS_BASE_AMOUNTget_intr   r#   r   deletewherestatusr   AWAITING_CONFIRMATIONr   in_r   get_not_confirmed_statusesr   r	   r7   CREW_MAX_CHEST_AMOUNT_RESETr
   selectcrewr<   usernot_inreset_levelapplicationcreate_task)r+   force_end_all_active_gamesremove_all_betsr0   
conditions	case_stmtvalid_contributionss          r?   reset_bountyr_   5   s      \[[[[[      @?????     /'
"
"""""""" 	Kt{T%88KKKSSUUU [1_ 3 5 5 EE!!1	
 +/S?GGII	I1M*J T:t{Q77IKy!!!))+++  	K%%%--/// -CC giii .IKKLL giii 	K"""**,,, 	KA&&&..000 ##%%%
  ? G G I II+3355	
*J T:t'899IK	]^  giii 6<>>DD#(;ty!!''3N3S(STT	U   &((..'*11II5HIII   giii 	 	KD)))11333 ##$:$:7$C$CDDDDDrA   FTrU   amountrF   should_update_locationpending_belly_amountaddshould_saveshould_affect_pending_bountycheck_for_loantax_event_typeevent_idraise_error_if_negative_bountyopponent
should_taxc                 
  K   ddl m} ||t          d          |
||
|t          d          |	|dk    rd}n|r|}ddlm}  |            }|                                5  t          j        | j                  }|j	        | _	        |j
        | _
        |j        | _        |j        | _        | j
        }|s| xj	        |z  c_	        |r| xj
        ||n|z  c_
        | j	        dk     r|rt          j        d| j         d	| j	         d
| d||                                nd dd                    t#          j                               
           t'          t(          j                            t/          |                              |r|                                  	 ddd           dS |r| xj
        ||n|z  c_
        | j
        dk     rh|dk    rbt          j        d| j         d| d||n| d| j
         d||                                nd dt#          j                                d| _
        |r|                                  |dk    r|s	 ddd           dS |                                 r	 ddd           dS |dk    r:|||ndz
  }|}|}t7          j        | j        |          }|rt;          j        |          }|dk    rt?          |           stA          | |          }||z
  }||z  }d}|
tC                      }| |_"        |
j#        |_$        ||_%        | j        |_&        ||_'        tQ          |          |_)        tQ          tU          |                     |_+        |                                 | ,                                rt[          t\          j/        |||            | xj        |z  c_        | xj        |z  c_        |	r| 0                                }|}|D ]v}tc          |td          j3        4                                          }|5                    tm          |                    }|7                    ||           d{V  ||z  }||z  }w| xj	        |z  c_	        |r|                                  |
tq          j9                    v r)|j:        ;                    ty          | ||                     ddd           n# 1 swxY w Y   |r&|t          d           || ||           d{V  dS dS )aF  
    Adds a bounty to a user
    :param context: Telegram context
    :param user: The user to add the bounty to
    :param amount: The amount to add to the bounty
    :param update: Telegram update
    :param should_update_location: Whether to update the user's location
    :param pending_belly_amount: How much of the amount is from pending belly, so not newly
    acquired. Will be used to calculate eventual taxes
    :param add: Whether to add or remove the bounty
    :param should_save: Whether to save the user
    :param should_affect_pending_bounty: Whether to affect the pending bounty
    :param check_for_loan: Whether to check for an expired bounty loan when adding bounty
    :param tax_event_type: The tax event type
    :param event_id: The event id
    :param raise_error_if_negative_bounty: Whether to raise an error if the user has negative
    :param opponent: The opponent from which the bounty is being taken
    contribution if there is an active challenge
    bounty after the update
    :param should_tax: Whether to tax the bounty

    :return: The updated user
    r   )update_locationNz0Amount or pending belly amount must be specifiedz6Tax event type and event id must be specified togetherT)initzUser z has negative bounty: z after removing z bounty in event None
 u3   ⚠️ NEGATIVE PENDING BOUNTY CLAMPED ⚠️
User z had pending bounty z, attempted to remove z, result would be z. Clamped to 0.
Event: z
Stack trace:
)	tax_eventrU   z.Context is required when updating the location)=src.service.location_servicerm   
ValueErrorsrc.chat.manage_messagern   atomicr   	get_by_idr<   r1   r2   r6   total_gained_bounty_unmodifiedloggingwarningto_dictjoin	tracebackformat_stackr   phrasesACTION_INSUFFICIENT_BOUNTYformatr*   saveerroris_arrested_permanentr   get_tax_breakdownr   get_amount_from_listr"   r    r   rU   value
event_typerh   starting_amountr`   r)   breakdown_listr!   deduction_listis_crew_memberr   r   
CREW_CHESTget_expired_bounty_loansr'   rI   BOUNTY_LOAN_GARNISH_PERCENTAGE	get_floatget_maximum_payable_amountintpayr   get_contribution_eventsrX   rY   add_dbf_contribution)rU   r`   r+   rF   ra   rb   rc   rd   re   rf   rg   rh   ri   rj   rk   rm   rn   dbrefreshed_userprevious_pending_bountynet_amount_without_pendingnet_amount_after_taxamount_to_addtax_breakdown
tax_amountrr   expired_loansamount_for_loansloanamount_for_repays                                 r?   add_or_remove_bountyr      sK     P =<<<<<~.6KLLL"h&:("2QRRR',@1,D,D'+$$	% &%,,,,,,	B	 C C#~dg66$+,;#1#E .<.[+"&"5  	KK6!KK+ ##2:FF@T## {Q#A=DG = =4; = == =+1+=v~~'''6= = !7!9!9::= =   *6==>QRX>Y>YZZ    		?C C C C C C C CB ( 	-A-I66Occ"Q&&+Ba+G+G@ G@ @9P@ @5I5Q66Wk@ @ (,':@ @ 392Dfnn...&	@ @
 &/%;%=%=@ @   '(# 		Q;;5;gC C C C C C C Cl %%'' 	oC C C C C C C Cr A::)/(<(H$$a*& $> "M 7G6X(*D7 7M  /D]SS
>>*I$*O*O>!/8" "J ,F
+R(!Z/M 8<I%14B4D4D	)-	/=/C	,-5	*484L	1+E	(3H3W3W	03HI[\`IaIa3b3b	0!((( **,, (5@&&/!%	    $$(<<$$//3GG// 9 $ = = ? ?#7 ) 9 9D'E(#*L*V*V*X*X( ($ (,'F'FsK[G\G\']']$ ((#3V<<<<<<<<< "%55M$(88$$KK=(KK 		 !F!H!HHH#//(/I8TT  CC C C C C C C C C C C C C C CL  5?MNNNodGV444444444445 5s'   &D=S0B(S%SISSSc                    | dk    r|j         S 	 t          |                                                     dd                              dd                    S # t          $ r t          | t          j                  cY S w xY w)zz
    Get the wager amount
    :param amount: The wager amount
    :param user: The user
    :return: The wager amount
    *,rq   .)r1   r   stripreplacert   r(   cMAGNITUDE_AMOUNT_TO_NUMBER)r`   rU   s     r?   get_amount_from_stringr   `  s     }}{P6<<>>))#r22::3CCDDD P P P)&!2NOOOOOPs   AA $A?>A?	wager_strrequired_bellyadd_delete_buttoninbound_keyboardprevious_screens"previous_screen_list_keyboard_infoshould_validate_user_has_amountsend_error_message raise_belly_validation_exceptionc           
      J  K   	 t          |t                    r|}n@	 t          ||          }n.# t          t          f$ r t          t          j                  w xY w|	rD|j        |k     r9t          t          j	        
                    t          |                              |?||k     r9t          t          j        
                    t          |                              n?# t
          $ r2}|
r!t          ||j        | ||||           d{V  |r|Y d}~dS d}~ww xY wdS )a  
    Validates the wager. Checks if the wager is a valid number, the user has enough belly, and if
    the wager is
    higher than the required belly
    :param update: Telegram update
    :param context: Telegram context
    :param user: The user to validate the wager for
    :param wager_str: The wager string
    :param required_belly: The required belly
    :param add_delete_button: Whether to add a delete button to the keyboard
    :param inbound_keyboard: The inbound keyboard
    :param previous_screens: The previous screens, for the back button if in private chat
    :param previous_screen_list_keyboard_info: The previous screen list keyboard info, for the back
    button if in private
    :param should_validate_user_has_amount: Whether to validate that the user has the amount
    :param send_error_message: Whether to send an error message if the wager is invalid
    :param raise_belly_validation_exception: Whether to raise a BellyValidationException if the
    wager is invalid
    :return: Whether the wager is valid
    N)rF   r   r   r   r   FT)
isinstancer   r   AttributeErrorrt   r   r   ACTION_INVALID_WAGER_AMOUNTr1   r   r   r*   ACTION_WAGER_LESS_THAN_MINr$   message)rF   r+   rU   r   r   r   r   r   r   r   r   r   wageres                 r?   validate_amountr   r  s     F#i%% 	TEET3ItDD"J/ T T T.w/RSSST + 	t{U/B/B*299:Me:T:TUU  
 %%.*@*@*299:Mn:]:]^^   $    		4	"3!1!13U          , 	Guuuuu" 4s,   C$ . C$ +AB
C$ $
D .'DD bellyc                     t          | t          j                                        z            t          j                                        z  S )z
    Rounds the belly up to the nearest given defined amount
    :param belly: The belly to round up
    :return: The rounded belly
    )r   rI   BELLY_UPPER_ROUND_AMOUNTrK   )r   s    r?   round_belly_upr     s?     	US199;;;<<

&
.
.
0
0	1rA   c                     t           j                             t           j        j                  } 	 t	          t
          j                                        |           }t          |          r|S |t          j	        d          z   } W)zP
    Get the next bounty reset time
    :return: The next bounty reset time
    Tstart_datetime   seconds)
datetimenowtimezoneutcr   rI   CRON_SEND_LEADERBOARDgetshould_reset_bounty	timedelta)r   next_run_times     r?   get_next_bounty_reset_timer     s     &**8+<+@AAN	G$%))++N
 
 
 }-- 	!  &);A)F)F)FF	GrA   c                  8    t          t                                S )zz
    Get the remaining duration to the next bounty reset
    :return: The remaining duration to the next bounty reset
    )r   r   r;   rA   r?   !get_duration_to_next_bounty_resetr     s     ""<">">???rA   c                     t           j                             t           j        j                  } 	 t	          t
          j                                        |           }t          |          r|S |t          j	        d          z
  } W)zX
    Get the previous bounty reset time
    :return: The previous bounty reset time
    Tr   r   r   )
r   r   r   r   r   rI   r   r   r   r   )r   previous_run_times     r?   get_previous_bounty_reset_timer     s     &**8+<+@AAN	K,%))++N
 
 
 011 	%$$*X-?-J-J-JJ	KrA   run_timec                    t          t          j                                        | t	          j        d          z             }| j        |j        k    r| j        dz
  dz  dk    p| j        dk    o| j        dz
  dz  dk    S )z
    Checks if the bounty should be reset given the run time.
    Bounties are reset on the last leaderboard of every even month.

    :param run_time: The run time
    :return: Whether the bounty should be reset
    r   )millisecondsr   r3   r   )r   rI   r   r   r   r   monthday)r   r   s     r?   r   r     s     !!%%''("4!"D"D"DD  M Nm11Sx~7IQ6NRS6S ;x~1Q6!;rA   senderreceiverbase_taxc                 B   |}t          |           s|t          |          rt          |           rt          |           nt          |          }|t          j        t          j        fv rdS |t          j        t          j        fv r;t          |           r,t          |t          j	        
                                          }|A|                     |          r,t          |t          j        
                                          }t          | t          j        |          }|S )z
    Get the transaction tax
    :param base_tax: The base tax
    :param sender: The sender
    :param receiver: The receiver
    :return: The transaction tax
    Nr   )r&   r%   r   ADMINLEGENDARY_PIRATEPIRATE_KINGWARLORDr'   rI   $PIRATE_KING_TRANSACTION_TAX_DISCOUNTr   in_same_crewCREW_TRANSACTION_TAX_DISCOUNTr   r   GIFT_LOAN_TAX)r   r   r   tax	boss_types        r?   get_transaction_taxr     s    CF  4h9O9O 4%1&%9%9VM&!!!}X?V?V 	
 )BCCC18/1ABBB|TZG[G[B0#BLLNN C
  3 3H = =,S#2S2]2]2_2_`` F$9$G
M
MCJrA   )NNNFNTFFTNNTNT)NTNNNTTF)er   ry   r}   mathr   peeweer   src.tg_compatr   src.tg_compat.extr   	constantsr   resources.EnvironmentEnvironmentrI   resources.phrasesr   src.model.BountyGiftr   src.model.BountyLoanr   src.model.Crewr	   %src.model.CrewMemberChestContributionr
   src.model.DavyBackFightr   src.model.IncomeTaxEventr   src.model.Userr   src.model.enums.BossTyper    src.model.enums.BountyGiftStatusr    src.model.enums.BountyLoanStatusr   src.model.enums.Locationr   src.model.enums.Screenr   1src.model.enums.devil_fruit.DevilFruitAbilityTyper   +src.model.enums.income_tax.IncomeTaxBracketr   -src.model.enums.income_tax.IncomeTaxBreakdownr   0src.model.enums.income_tax.IncomeTaxContributionr   -src.model.enums.income_tax.IncomeTaxEventTyper   src.model.error.CommonChatErrorr   src.model.error.CustomExceptionr   src.model.pojo.Keyboardr   src.service.date_servicer   r   r   #src.service.davy_back_fight_servicer   r   src.service.devil_fruit_servicer   src.service.income_tax_servicer    r!   r"   rs   r#   src.service.message_servicer$   src.service.user_servicer%   r&   src.utils.math_utilsr'   src.utils.string_utilsr(   r)   r*   DEFAULT_TYPEr_   r   boolr   strr   listdictr   floatr   r   r   r   r   r   r;   rA   r?   <module>r     s                                 * * * * * *     # # # # # # # # # # # # + + + + + + + + + + + +       M M M M M M 1 1 1 1 1 1 3 3 3 3 3 3       - - - - - - = = = = = = = = = = = = 8 8 8 8 8 8 ) ) ) ) ) ) S S S S S S H H H H H H L L L L L L V V V V V V L L L L L L ? ? ? ? ? ? D D D D D D , , , , , , [ [ [ [ [ [ [ [ [ [ X X X X X X = = = = = =            8 7 7 7 7 7 J J J J J J @ @ @ @ @ @ @ @ ? ? ? ? ? ?         aE 9 aEd aE aE aE aEL )-#( $).)-+/D5 D5
D5D5 &D5 	D5
 !D5 D5 
D5 D5 #'D5 D5 'D5 D5 %)D5 D5 D5  
!D5 D5 D5 D5NP3 Pd Ps P P P P. "!%%)/3,0#-2H HH&H H Sy	H
 H H H 6lH )-H &*H H '+H 
H H H HV	% 	C 	 	 	 	GH$5 G G G G&@3 @ @ @ @K(9 K K K K&( t    ,       %            rA   