o
    gi%                     @   sZ  d dl mZ d dlmZ d dlmZmZ d dlmZmZm	Z	 d dl
mZ d dlmZ d dlmZ d dlmZmZ d d	lmZ d d
lZd dlmZ d d
lZedZdededefddZdedededededefddZdedededededefddZdedededededefddZ d"dedededefddZ!d"dedededefd d!Z"d
S )#    )Session)HTTPException)OptionalDict)datetimedate	timedelta)
UserPoints)PointTransaction)
StepRecord)get_setting_floatget_setting_int)nowN)func	adimsayardbuser_idreturnc                 C   sL   |  ttj|k }|s#t|dd}| | |   | | |jS )u8   사용자의 현재 보유 포인트를 조회합니다.r   r   total_points)	queryr	   filterr   firstaddcommitrefreshr   )r   r   user_points r   "/app/app/services/point_service.pyget_user_points   s   

r   amounttransaction_typedescriptionc                 C   s   |dkr
t ddd| ttj|k }|s$t|dd}| | | j|7  _t||||t	 d}| | | 
  | | |S )uz  
    사용자에게 포인트를 적립합니다.
    
    Args:
        db: 데이터베이스 세션
        user_id: 사용자 ID
        amount: 적립할 포인트 양 (양수)
        transaction_type: 트랜잭션 유형 (step, achievement, referral_bonus 등)
        description: 트랜잭션 설명
        
    Returns:
        업데이트된 UserPoints 객체
    r     Points amount must be positivestatus_codedetailr   r   r!   r    r"   
created_at)r   r   r	   r   r   r   r   r   r
   r   r   r   )r   r   r    r!   r"   r   transactionr   r   r   
add_points   s$   


r+   c                 C   s   |dkr
t dddt| |}||k rt dd| d| d| ttj|k }| j|8  _t||| |t	 d}| 
| |   | | |S )u  
    사용자의 포인트를 차감합니다.
    
    Args:
        db: 데이터베이스 세션
        user_id: 사용자 ID
        amount: 차감할 포인트 양 (양수로 입력하면 내부적으로 음수 처리)
        transaction_type: 트랜잭션 유형 (redeem 등)
        description: 트랜잭션 설명
        
    Returns:
        업데이트된 UserPoints 객체
        
    Raises:
        HTTPException: 포인트 부족 시 발생
    r   r#   r$   r%   zNot enough points. Required: z, Available: r(   )r   r   r   r	   r   r   r   r   r
   r   r   r   r   )r   r   r    r!   r"   current_pointsr   r*   r   r   r   deduct_pointsK   s*   


r-   order_numberorder_idc                 C   s   d| d}t | ||d|dS )u3  
    주문에 대한 포인트를 차감합니다.
    
    Args:
        db: 데이터베이스 세션
        user_id: 사용자 ID
        amount: 차감할 포인트 양
        order_number: 주문 번호
        order_id: 주문 ID
        
    Returns:
        업데이트된 UserPoints 객체
    zOrder #z paymentredeem)r   r   r    r!   r"   )r-   )r   r   r    r.   r/   r"   r   r   r   deduct_points_for_order   s   r1   country_codec                 C   s   ddl m} | }| ttj|ktj|k }|r&t	dd |D nd}| t
t
j|kt
jdktt
j|k }d}|D ]}	td|	j}
|
rY|t|
d7 }qD	 qD|| }|dk red}|d d }|||d	S )
ud  
    사용자의 아직 포인트로 전환되지 않은 걸음수를 계산합니다.
    포인트는 1000걸음 단위로 전환됩니다.
    
    Args:
        db: 데이터베이스 세션
        user_id: 사용자 ID
        country_code: 국가 코드 (설정값 조회용)
        
    Returns:
        계산된 정보를 담은 Dictionary
    r   )r   c                 s       | ]}|j V  qd S Nsteps_count.0recordr   r   r   	<genexpr>       z/calculate_unconverted_points.<locals>.<genexpr>stepzfrom (\d+) steps     )unconverted_stepspotential_pointsconvertible_points)r   r   todayr   r   r   r   record_dateallsumr
   r!   r   r)   researchr"   intgroup)r   r   r2   r   rB   recordstotal_stepsZtransactionsZconverted_stepsZtxmr?   convertible_stepsr   r   r   calculate_unconverted_points   s<   

rN   c                 C   sh  t | ||}|d }|dk rddd|d t| |dS t }| ttj|ktj|k	 }|r;t
dd	 |D nd}t| d
|}t| d|}	||krO|	nd}
t||
 }t|d|d| d| d|
 dd}| | | ttj|k }|r| j|7  _nt||d}| | |   ddlm} || || |d | }dd| d|||jdS )uh  
    걸음 기록에서 아직 전환되지 않은 걸음수를 포인트로 전환합니다.
    포인트는 1000점 단위로만 전환됩니다.
    
    Args:
        db: 데이터베이스 세션
        user_id: 사용자 ID
        country_code: 국가 코드 (설정값 조회용)
        
    Returns:
        전환 결과를 담은 Dictionary
    rA   r>   Fz:Not enough points to convert. Minimum 1000 steps required.r   r@   )successmessageZconverted_pointsZremaining_unconverted_pointsZcurrent_total_pointsc                 s   r3   r4   r5   r7   r   r   r   r:      r;   z*convert_steps_to_points.<locals>.<genexpr>STEP_THRESHOLDSTEP_MULTIPLIERr=   r<   zStep points conversion: z points from z steps with multiplier .)r   r!   r    r"   r   )UserServiceTzSuccessfully converted z points from steps.)rN   r   r   rB   r   r   r   r   rC   rD   rE   r   r   rH   r
   r   r	   r   r   r   app.services.user_servicerT   award_referral_chain_bonus)r   r   r2   Zconversion_inforM   rB   rJ   Ztotal_steps_day	thresholdZstep_multiplier
multiplierZconversion_pointspoint_txr   rT   Zremaining_stepsr   r   r   convert_steps_to_points   sV   	



rZ   r4   )#sqlalchemy.ormr   fastapir   typingr   r   r   r   r   app.models.user_pointsr	   app.models.point_transactionr
   app.models.step_recordr   app.services.admin_servicer   r   app.core.timer   logging
sqlalchemyr   rF   	getLoggerloggerrH   r   strr+   r-   r1   rN   rZ   r   r   r   r   <module>   sn    

/
9
 8