o
    g?f                     @   s  d dl mZ d dlmZmZmZ d dlmZ d dlm	Z	m
Z
 d dlZd dlmZ d dlmZmZ d dlmZ d d	lmZ d d
lmZ edZdddeejeejeejeejeejeejd	Z d?dedee dee fddZ!d?dededee dee fddZ"d?dededee defddZ#d?dededee de$fddZ%d?dededee de&fddZ'	d?dedede
dee def
dd Z(deddfd!d"Z)ded#ed$edee fd%d&Z*dedee fd'd(Z+ded)e&d*edefd+d,Z,ded-e&deeef fd.d/Z-d@ded1e&d2e&dee fd3d4Z.ded5e&d6edeeef fd7d8Z/ded9eeef deeef fd:d;Z0ded<e&deeef fd=d>Z1dS )A    )Session)ListOptionalDict)AdminSetting)AdminSettingCreateAdminSettingUpdateN)settings)HTTPExceptionstatus)Any)Order)Product	adimsayarz0.01Z7000z2.0)	ZSTEP_BASE_RATEZSTEP_THRESHOLDZSTEP_MULTIPLIERACHIEVEMENT_STEP_GOALACHIEVEMENT_BONUSZREFERRAL_BONUS REFERRAL_DIRECT_BONUS_PERCENTAGEREFERRAL_CHAIN_DECAYREFERRAL_MAX_LEVELdbcountry_codereturnc                 C   s&   |  t}|r|tj|k}| S )u{   
    모든 관리자 설정을 조회합니다. country_code가 제공되면 해당 국가 설정만 반환합니다.
    )queryr   filterr   all)r   r   r    r   "/app/app/services/admin_service.pyget_all_settings   s   
r   setting_namec                 C   sP   |r|  ttj|ktj|k }|r|S |  ttj|ktjdk S )u   
    특정 설정을 조회합니다. country_code가 제공되면 해당 국가 설정을 우선 조회하고,
    없는 경우 country_code가 None인 기본 설정을 반환합니다.
    N)r   r   r   r   r   firstr   r   r   settingr   r   r   get_setting#   s   

r"   c                 C   s,   t | ||}|r|jdur|jS t|dS )uk   
    설정 값을 문자열로 반환합니다. 설정이 없는 경우 기본값을 반환합니다.
    N )r"   setting_valueDEFAULT_SETTINGSgetr    r   r   r   get_setting_value7   s   r'   c                 C   st   t | ||}zt|W S  ttfy9   td| d| d ztt|dW  Y S  ttfy8   Y Y dS w w )u\   
    설정 값을 실수로 반환합니다. 변환 실패 시 0.0을 반환합니다.
    Failed to convert setting  with value 'z
' to floatz0.0g        )r'   float
ValueError	TypeErrorloggererrorr%   r&   r   r   r   valuer   r   r   get_setting_floatB   s   
r1   c                 C   s|   t | ||}ztt|W S  ttfy=   td| d| d zttt|dW  Y S  ttfy<   Y Y dS w w )uZ   
    설정 값을 정수로 반환합니다. 변환 실패 시 0을 반환합니다.
    r(   r)   z' to int0r   )	r'   intr*   r+   r,   r-   r.   r%   r&   r/   r   r   r   get_setting_intQ   s   r4   update_datac                 C   s   |  ttj|ktj|k }|r!|j|_|jdur |j|_nt||j|dur+|n|jd}| | |   | 	| |S )uO   
    설정을 업데이트하거나 없는 경우 새로 생성합니다.
    Nr   r$   r   )
r   r   r   r   r   r   r$   addcommitrefresh)r   r   r5   r   r!   r   r   r   update_setting`   s(   




r:   c                 C   s\   t  D ]#\}}| ttj|ktjdk }|s't||dd}| | q| 	  dS )uu   
    애플리케이션 시작 시 기본 설정이 존재하는지 확인하고, 없는 경우 생성합니다.
    Nr6   )
r%   itemsr   r   r   r   r   r   r7   r8   )r   namer0   r!   r   r   r   ensure_default_settings   s    

r=   emailpasswordc              
   C   s  zddl m} ddlm}m} ddlm} ddlm} ddlm	} ddl
m}	 td|  | |	|	j|k }
|
sItd	|  W d
S |||
js[td|  W d
S |
jdkrktd|  W d
S |
jsytd|  W d
S | |
_| |
 |   | |
 ||
jd}||
jd}||d|
j|
j|
j|
j|
j|
jdd}|W S  ty } ztjdt | dd  d
}~ww )z
    Admin authentication function.
    Authenticates user credentials and verifies that the user has admin privileges.
    Returns admin user data with tokens if authentication is successful, None otherwise.
    r   )UserService)create_access_tokencreate_refresh_token)NotificationService)now)pwd_contextUserz*Attempting admin authentication for user: zUser not found with email: NzInvalid password for admin: z#Inactive admin attempted to login: z&Non-admin user attempted admin login: )subjectbearer)idr>   
first_name	last_namer   is_admin)access_tokenrefresh_token
token_typeuserzAdmin authentication error: Texc_info)!app.services.user_servicer@   app.core.securityrA   rB   !app.services.notification_servicerC   app.core.timerD   rE   app.models.userrG   r-   infor   r   r>   r   warningverifyr?   r   rM   
last_loginr7   r8   r9   rJ   rK   rL   	Exceptionr.   str)r   r>   r?   r@   rA   rB   rC   rD   rE   rG   rQ   rN   rO   responseer   r   r   authenticate_admin   sX   


ra   c              
   C   s   ddl m} ddlm} | |j|j|j|j|j	|j
||j|jk }g }|D ]}||j|j|j	|j
|j|jd q*|S )u   
    모든 사용자의 포인트 정보를 조회합니다.
    
    Args:
        db (Session): 데이터베이스 세션
    
    Returns:
        List[Dict]: 모든 사용자의 포인트 정보 목록
    r   )
UserPointsrF   )user_idr>   rK   rL   total_points
updated_at)app.models.user_pointsrb   rX   rG   r   rc   rd   re   r>   rK   rL   joinrJ   r   append)r   rb   rG   resultsZuser_points_listresultr   r   r   get_all_user_points   s6   


	rk   rc   	user_datac           	      C   s   ddl m} | ||j|k }|s ttjd| ddz9|	 D ]
\}}t
||| q%| | |   | | |j|j|j|j|j|j|j|j|j|j|jd}|W S  tyu } z|   ttjdt| dd}~ww )	u  
    관리자 권한으로 사용자 정보를 업데이트합니다.
    
    Args:
        db (Session): 데이터베이스 세션
        user_id (int): 업데이트할 사용자의 ID
        user_data (Dict): 업데이트할 사용자 정보
        
    Returns:
        Dict: 업데이트된 사용자 정보
        
    Raises:
        HTTPException: 사용자를 찾을 수 없거나 업데이트 중 오류가 발생한 경우
    r   rF   zUser with id 
 not foundstatus_codedetail)rJ   r>   rK   rL   
phone_codephonegender
birth_datedaily_step_goalr   re   zFailed to update user: N)rX   rG   r   r   rJ   r   r
   r   HTTP_404_NOT_FOUNDr;   setattrr7   r8   r9   r>   rK   rL   rq   rr   rs   rt   ru   re   r]   rollbackHTTP_500_INTERNAL_SERVER_ERRORr^   )	r   rc   rl   rG   rQ   keyr0   Z	user_infor`   r   r   r   update_user_by_admin   sD   


r{   category_idc              
   C   sB  ddl m} ddlm} ddlm} z| ||j|k	 }|s-t
tjd| dd|j}|j}| ttj|k }|dkrRt
tjd| d	| d
d|j|j|jd}	| | |   | ||j|k	 }
|
durtd|  t
tjdd| |||j|k|j|k	 }|durtd|j d|j d|j  d|	|j|j|jdddW S td| d|	d   d|	dW S  |y } z|   tdt|  t
tjdt| dd}~w t
y     ty  } z|   tdt|  t
tjdt| dd}~ww )u  
    관리자 권한으로 상품 카테고리를 삭제합니다.
    
    Args:
        db (Session): 데이터베이스 세션
        category_id (int): 삭제할 상품 카테고리의 ID
        
    Returns:
        Dict: 삭제 성공 메시지와 삭제된 카테고리 ID
        
    Raises:
        HTTPException: 카테고리가 존재하지 않거나 관련 제품이 있어 삭제할 수 없는 경우
    r   )ProductCategory)IntegrityError)or_zProduct category with id rm   rn   zCannot delete category with id z because it has z- products. Remove or reassign products first.)rJ   coder<   Nz)Category still exists after deletion: ID=zTFailed to delete product category. The category still exists after deletion attempt.z,Found duplicate category after deletion: ID=z, Code=z, Name=zOCategory with ID {category_id} was deleted, but a similar category still existsu   자동 복제 방지 시스템이 감지되었습니다. 데이터베이스 트리거나 외부 프로세스가 삭제된 카테고리를 다시 생성했을 수 있습니다.)messagedeleted_categoryZsimilar_categoryrZ   z*Successfully deleted product category: ID=r<   z%Product category deleted successfully)r   r   z*IntegrityError deleting product category: z9Cannot delete this category due to database constraints: z!Error deleting product category: zBAn unexpected error occurred while deleting the product category: )Zapp.models.product_categoryr}   sqlalchemy.excr~   
sqlalchemyr   r   r   rJ   r   r
   r   rv   r   r<   r   r|   countHTTP_400_BAD_REQUESTdeleter8   r-   r.   ry   rZ   rY   rx   r^   r]   )r   r|   r}   r~   r   categoryZcategory_codeZcategory_nameZproducts_countZcategory_infoZdeleted_checkZduplicate_checkr`   r   r   r   delete_product_category8  s   


"r   d   skiplimitc                 C   sn  z|  ttj || }|st	d g W S g }|D ]c}g }|j
D ]:}|  ttj|jk }|r>|jnd}	|rE|jnd}
|j|j|j|j|j|j|j |	|
|jd
}|| q)|j|j|j|j|j|j|jdd||j |j d}|| q"t	dt| d |W S  ty } ztj dt!| d	d
 t"ddt!| dd}~ww )u#  
    모든 사용자의 주문정보를 조회합니다.
    
    Args:
        db (Session): 데이터베이스 세션
        skip (int): 건너뛸 레코드 수
        limit (int): 조회할 최대 레코드 수
        
    Returns:
        List[Dict]: 모든 주문 정보 목록
    zNo orders found in the databaseN

product_idquantityrJ   order_idpoints_per_itemrd   
created_atproduct_nameproduct_imageZproduct_priceFrJ   rc   order_numberrd   r   
address_idshipping_detailsZsave_addressZaddress_titler;   r   re   z
Retrieved z orders from the databasezError retrieving orders: TrR   i  Internal server error: rn   )#r   r   order_byr   descoffsetr   r   r-   rY   r;   r   r   rJ   r   r   r<   	thumbnailr   r   r   rd   	isoformatrh   rc   r   r   r   r   re   lenr]   r.   r^   r
   )r   r   r   ordersrj   orderorder_itemsitemproductr   r   
order_item
order_infor`   r   r   r   get_all_orders  sZ   &

r   r   
new_statusc                 C   s  zg d}|  }||vrttjdd| d| ttj|k	 }|s4ttj
d| dd|j}||_|   | | td| d| d	|  g }|jD ]:}| ttj|jk	 }|rk|jnd
}	|rr|jnd
}
|j|j|j|j|j|j|j |	|
|jd
}|| qV|j|j|j|j|j|j|jdd
||j |j d}|W S  ty     t y } ztj!dt"| dd ttj#dt"| dd
}~ww )u  
    주문 상태를 업데이트합니다.
    
    Args:
        db (Session): 데이터베이스 세션
        order_id (int): 업데이트할 주문 ID
        new_status (str): 새로운 주문 상태 (DELIVERED, PROCESSING, PENDING, CANCELLED)
        
    Returns:
        Dict[str, Any]: 업데이트된 주문 정보
        
    Raises:
        HTTPException: 주문이 존재하지 않거나 잘못된 상태 값이 제공된 경우
    )Z	DELIVERED
PROCESSINGPENDING	CANCELLEDz&Invalid status value. Must be one of: z, rn   zOrder with ID rm   z!Order status updated - Order ID: z, Old status: z, New status: Nr   Fr   zError updating order status: TrR   r   )$upperr
   r   r   rg   r   r   r   rJ   r   rv   r8   r9   r-   rY   r;   r   r   r<   r   r   r   r   rd   r   r   rh   rc   r   r   r   re   r]   r.   r^   ry   )r   r   r   Zvalid_statusesr   Z
old_statusr   r   r   r   r   r   r   r`   r   r   r   update_order_status  sx   


r   ad_datac           	   
   C   s8  ddl m} zm|d }| ||j|k|j  }|r<|D ]}| jd7  _| | q"t	
dt| d ||d ||d d	}| | |   | | |j|j|j|j|j d
}t	
d|j d|j  |W S  ty } z|   t	jdt| dd ttjdt| dd}~ww )u\  
    새로운 광고를 생성합니다. 중복된 video_list_order 값이 있으면 자동으로 조정합니다.
    
    Args:
        db (Session): 데이터베이스 세션
        ad_data (Dict[str, Any]): 광고 데이터 (ad_url, video_list_order, ad_video_points)
        
    Returns:
        Dict[str, Any]: 생성된 광고 정보
    r   Advertisementvideo_list_order   zAdjusted order for z existing advertisementsad_urlad_video_points)r   r   r   )rJ   r   r   r   r   z)Advertisement created successfully - ID: z	, Order: zError creating advertisement: TrR   z Failed to create advertisement: rn   N)app.models.advertisementr   r   r   r   r   r   r   r7   r-   rY   r   r8   r9   rJ   r   r   r   r   r]   rx   r.   r^   r
   r   ry   )	r   r   r   Zrequested_orderZ&existing_ads_with_same_or_higher_orderZexisting_adZnew_adad_infor`   r   r   r   create_advertisementG  sL   

r   ad_idc              
   C   s   ddl m} z<| ||j|k }|s!ttjd| dd|j|j	|j
|jd}| | |   td|  d|d	W S  tyJ     tyq } z|   tjd
t| dd ttjdt| dd}~ww )u   
    광고를 삭제합니다.
    
    Args:
        db (Session): 데이터베이스 세션
        ad_id (int): 삭제할 광고 ID
        
    Returns:
        Dict[str, Any]: 삭제 결과 메시지
    r   r   zAdvertisement with ID rm   rn   )rJ   r   r   r   z)Advertisement deleted successfully - ID: z"Advertisement deleted successfully)r   Zdeleted_advertisementzError deleting advertisement: TrR   z Failed to delete advertisement: N)r   r   r   r   rJ   r   r
   r   rv   r   r   r   r   r8   r-   rY   r]   rx   r.   r^   ry   )r   r   r   adr   r`   r   r   r   delete_advertisement  s<   

r   )N)r   r   )2sqlalchemy.ormr   typingr   r   r   Zapp.models.admin_settingr   Zapp.schemas.admin_settingr   r   loggingapp.core.configr	   Zapp_settingsfastapir
   r   r   Zapp.models.orderr   Zapp.models.productr   	getLoggerr-   r^   r   r   REFERRAL_SIGNUP_BONUSr   r   r   r%   r   r"   r'   r*   r1   r3   r4   r:   r=   ra   rk   r{   r   r   r   r   r   r   r   r   r   <module>   s^    
 $	   
!A(: m"F&\"@