o
    ?g)                     @   s   d dl Z d dlZ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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Zd d	lmZ ed
ZG dd deZG dd dZdS )    N)BytesIO)
UploadFile)ClientError)settings)BaseSettings)Field)HTTPException)Optional	adimsayarc                   @   sl   e Zd ZU edddZeed< edddZeed< edddZeed< edddZ	eed< G dd	 d	Z
d
S )Settings.AWS_S3_ENDPOINT_URL)envAWS_S3_BUCKETAWS_S3_BUCKET_NAMEAWS_ACCESS_KEY_IDAWS_SECRET_ACCESS_KEYc                   @   s   e Zd ZdZdZdZdS )zSettings.Configz.envTignoreN)__name__
__module____qualname__env_filecase_sensitiveextra r   r   "/app/app/services/media_service.pyConfig   s    r   N)r   r   r   r   r   str__annotations__r   r   r   r   r   r   r   r   r      s   
 r   c                   @   s   e Zd Zddededededef
ddZd	ed
ee fddZdd Zdeded
efddZ	defddZ
ddeded
efddZded
dfddZdS ) MediaServiceNs3_endpoint_urlbucket_name
access_key
secret_keyregion_namec                 C   sV   || _ || _|p| || _td| d| d| j  tjd|||| jd| _dS )u{  
        AWS S3 클라이언트를 초기화합니다.
        :param s3_endpoint_url: S3 엔드포인트 URL (예: "https://s3.eu-central-1.amazonaws.com")
        :param bucket_name: AWS S3 버킷 이름
        :param access_key: AWS_ACCESS_KEY_ID
        :param secret_key: AWS_SECRET_ACCESS_KEY
        :param region_name: (선택) 리전 이름. 필요 시 사용.
        z&MediaService initialized with bucket: z, endpoint: z
, region: Zs3)endpoint_urlZaws_access_key_idZaws_secret_access_keyr#   N)	r   r    _extract_region_from_endpointr#   loggerinfoboto3client	s3_client)selfr   r    r!   r"   r#   r   r   r   __init__   s   	zMediaService.__init__r$   returnc                 C   s2   ddl }|sdS d}|||}|r|dS dS )u   
        S3 엔드포인트 URL에서 리전 정보를 추출합니다.
        예: "https://s3.eu-central-1.amazonaws.com" -> "eu-central-1"
        r   N"s3[.-]([a-z0-9-]+)\.amazonaws\.com   )researchgroup)r+   r$   r0   aws_region_patternmatchr   r   r   r%   6   s   
z*MediaService._extract_region_from_endpointc                 C   s~   z| j j| jd W dS  ty>   z| j j| jd td| j d W Y dS  ty= } z	td|   d}~ww w )u   
        (필요 시) 버킷이 존재하지 않으면 새로 생성합니다.
        AWS S3의 경우 사전에 버킷을 생성하거나, 퍼블릭 접근 정책을 설정하는 것이 좋습니다.
        )BucketzBucket 'z
' created.zError creating bucket: N)r*   Zhead_bucketr    r   Zcreate_bucketr&   r'   error)r+   er   r   r   _create_bucketH   s   zMediaService._create_bucketfilefilenamec              
   C   sV   z| j |j| j| td|  |W S  ty* } z	td|   d}~ww )u   
        업로드된 파일 객체(file)를 S3 버킷에 업로드합니다.
        :param file: UploadFile 객체 (FastAPI UploadFile)
        :param filename: S3에 저장될 파일명 
        :return: 파일 키 (예: filename)
        zFile uploaded: zError uploading file to S3: N)r*   Zupload_fileobjr9   r    r&   r'   r   r6   )r+   r9   r:   errr   r   r   upload_fileX   s   zMediaService.upload_filefolder_namec              
   C   s   | ds	|d7 }z| jj| j|tddd td| d| j d W d
S  ty@ } ztd| d	t	|   d
}~ww )u   
        폴더 생성은 S3에서는 객체 키로 관리되므로, 빈 객체를 업로드하여 폴더를 생성하는 효과를 냅니다.
        /    application/octet-streamr5   KeyBodyContentTypezFolder 'z' created in bucket ''zError creating folder 'z': N)
endswithr*   
put_objectr    r   r&   r'   	Exceptionr6   r   )r+   r=   r7   r   r   r   create_folderg   s   
 zMediaService.create_folderprofiler<   folderc              
   C   s  z;t d|j d|  |ds| d}n|}|j}t d|  |s/t d d}tj|d 	 }|sBt d d	}t
  | }|| }t d
|  |j }|jd t|}	t d|	 d |	dkr{t d td|j}
|
s|dv rd}
n|dkrd}
n	|dkrd}
nd}
t d|
  t d| j d| d|
  | jj| j|t||
d}t d|  d| jv r| j}|sddl}d}||| j}|r|d}nd}d | j d!| d"| }t d#|  n9tj| j}|j d$|j  }|jr#|jdkr#|j!d}| | d| }n| d| }t d%|  t d&|  |W S  t"y` } zt jd't#| d(d) t$d*d+t#| d,d}~w t%y } zt jd-t#| d(d) t$d*d+t#| d,d}~ww ).u%  
        파일을 AWS S3의 특정 폴더에 업로드하고, 업로드된 파일의 전체 URL을 반환합니다.
        파일명은 고유한 UUID로 생성됩니다.
        예: "https://adimsayar.s3.eu-central-1.amazonaws.com/profile/bb3c2811-a2c1-40f9-b82c-731c2db7ff45.jpg"
        zUploading image to S3: z to folder: r>   zOriginal filename: z0Empty filename detected, generating generic namezunnamed_file.jpgr/   z)No file extension detected, assuming .jpg.jpgzGenerated file key: r   zFile size: z byteszFile content is empty)rL   z.jpegz
image/jpegz.pngz	image/pngz.gifz	image/gifr@   z!No content type provided, using: zUploading to bucket: z, key: z, content-type: rA   zUpload successful: zamazonaws.comNr.   zunknown-regionzhttps://z.s3.z.amazonaws.com/z"Using AWS S3 standard URL format: z://z)Using custom storage service URL format: zFinal uploaded image URL: zAWS S3 error uploading image: T)exc_infoi  zFailed to upload image: )status_codedetailz"Unexpected error uploading image: )&r&   r'   r:   rF   debugwarningospathsplitextloweruuiduuid4r9   readseeklenr6   
ValueErrorcontent_typer    r*   rG   r   r   r#   r0   r1   r2   urllibparseurlparseschemenetlocrstripr   r   r   rH   )r+   r<   rK   full_folderoriginal_filename	extensionunique_filenamefile_keyZfile_contentcontent_lengthr\   responseZregionr0   r3   r4   full_url
parsed_urlZbase_endpoint	base_pathr7   r   r   r   upload_imagey   s   





zMediaService.upload_imagepolicyc              
   C   sf   t |}z| jj| j|d td| j d W dS  ty2 } ztdt	|   d}~ww )uv   
        S3 버킷 정책을 업데이트합니다.
        :param policy: 정책 dict (AWS S3 정책 형식)
        )r5   Policyz"Bucket policy updated for bucket 'rE   zError updating bucket policy: N)
jsondumpsr*   Zput_bucket_policyr    r&   r'   rH   r6   r   )r+   rn   Zpolicy_jsonr7   r   r   r   update_bucket_policy   s   
z!MediaService.update_bucket_policy)N)rJ   )r   r   r   r   r,   r	   r%   r8   r   r<   rI   rm   dictrr   r   r   r   r   r      s     ur   )iorV   rR   loggingrp   r   fastapir   r(   Zbotocore.exceptionsr   app.core.configr   pydantic_settingsr   pydanticr   r   urllib.parser]   typingr	   	getLoggerr&   r   r   r   r   r   r   <module>   s$    
