from pathlib import Path

from pydantic import Field
from pydantic_settings import BaseSettings, SettingsConfigDict

PROJECT_DIR = Path(__file__).resolve().parent

# 미디어 파일 저장 디렉토리
MEDIA_ROOT = PROJECT_DIR / "media"
MEDIA_ROOT.mkdir(exist_ok=True)

_base_config = SettingsConfigDict(
    env_file=PROJECT_DIR / ".env",
    env_ignore_empty=True,
    extra="ignore",
)


class ProjectSettings(BaseSettings):
    PROJECT_NAME: str = Field(default="CastAD")
    PROJECT_DOMAIN: str = Field(default="localhost:8000")
    VERSION: str = Field(default="0.1.0")
    DESCRIPTION: str = Field(default="FastAPI 기반 CastAD 프로젝트")
    ADMIN_BASE_URL: str = Field(default="/admin")
    DEBUG: bool = Field(default=True)

    model_config = _base_config


class APIKeySettings(BaseSettings):
    CHATGPT_API_KEY: str = Field(default="your-chatgpt-api-key")  # 기본값 추가
    SUNO_API_KEY: str = Field(default="your-suno-api-key")  # Suno API 키
    SUNO_CALLBACK_URL: str = Field(
        default="https://example.com/api/suno/callback"
    )  # Suno 콜백 URL (필수)
    CREATOMATE_API_KEY: str = Field(default="your-creatomate-api-key")  # Creatomate API 키

    model_config = _base_config


class CORSSettings(BaseSettings):
    # CORS (Cross-Origin Resource Sharing) 설정

    # 요청을 허용할 출처(Origin) 목록
    # ["*"]: 모든 출처 허용 (개발 환경용, 프로덕션에서는 구체적인 도메인 지정 권장)
    # 예: ["https://example.com", "https://app.example.com"]
    CORS_ALLOW_ORIGINS: list[str] = ["*"]

    # 자격 증명(쿠키, Authorization 헤더 등) 포함 요청 허용 여부
    # True: 클라이언트가 credentials: 'include'로 요청 시 쿠키/인증 정보 전송 가능
    # 주의: CORS_ALLOW_ORIGINS가 ["*"]일 때는 보안상 False 권장
    CORS_ALLOW_CREDENTIALS: bool = True

    # 허용할 HTTP 메서드 목록
    # ["*"]: 모든 메서드 허용 (GET, POST, PUT, DELETE, PATCH, OPTIONS 등)
    # 구체적 지정 예: ["GET", "POST", "PUT", "DELETE"]
    CORS_ALLOW_METHODS: list[str] = ["*"]

    # 클라이언트가 요청 시 사용할 수 있는 HTTP 헤더 목록
    # ["*"]: 모든 헤더 허용
    # 구체적 지정 예: ["Content-Type", "Authorization", "X-Custom-Header"]
    CORS_ALLOW_HEADERS: list[str] = ["*"]

    # 브라우저의 JavaScript에서 접근 가능한 응답 헤더 목록
    # []: 기본 안전 헤더(Cache-Control, Content-Language, Content-Type,
    #     Expires, Last-Modified, Pragma)만 접근 가능
    # 추가 노출 필요 시: ["X-Total-Count", "X-Request-Id", "X-Custom-Header"]
    CORS_EXPOSE_HEADERS: list[str] = []

    # Preflight 요청(OPTIONS) 결과를 캐시하는 시간(초)
    # 600: 10분간 캐시 (이 시간 동안 동일 요청에 대해 preflight 생략)
    # 0으로 설정 시 매번 preflight 요청 발생
    CORS_MAX_AGE: int = 600

    model_config = _base_config


class DatabaseSettings(BaseSettings):
    # MySQL 연결 설정 (기본값: 테스트 계정 및 poc DB)
    MYSQL_HOST: str = Field(default="localhost")
    MYSQL_PORT: int = Field(default=3306)
    MYSQL_USER: str = Field(default="test")
    MYSQL_PASSWORD: str = Field(default="")  # 환경변수에서 로드
    MYSQL_DB: str = Field(default="poc")

    # Redis 설정
    REDIS_HOST: str = "localhost"
    REDIS_PORT: int = 6379

    model_config = _base_config

    @property
    def MYSQL_URL(self) -> str:
        """비동기 MySQL URL 생성 (asyncmy 드라이버 사용, SQLAlchemy 통합 최적화)"""
        return f"mysql+asyncmy://{self.MYSQL_USER}:{self.MYSQL_PASSWORD}@{self.MYSQL_HOST}:{self.MYSQL_PORT}/{self.MYSQL_DB}"

    def REDIS_URL(self, db: int = 0) -> str:
        """Redis URL 생성 (db 인수로 기본값 지원)"""
        return f"redis://{self.REDIS_HOST}:{self.REDIS_PORT}/{db}"


class CrawlerSettings(BaseSettings):
    NAVER_COOKIES: str = Field(default="")

    model_config = _base_config


class AzureBlobSettings(BaseSettings):
    """Azure Blob Storage 설정"""

    AZURE_BLOB_SAS_TOKEN: str = Field(
        default="",
        description="Azure Blob Storage SAS 토큰",
    )
    AZURE_BLOB_BASE_URL: str = Field(
        default="https://ado2mediastoragepublic.blob.core.windows.net/ado2-media-public-access/ado2-media-original",
        description="Azure Blob Storage 기본 URL",
    )

    model_config = _base_config


class CreatomateSettings(BaseSettings):
    """Creatomate 템플릿 설정"""

    # 세로형 템플릿 (기본값)
    TEMPLATE_ID_VERTICAL: str = Field(
        default="e8c7b43f-de4b-4ba3-b8eb-5df688569193",
        description="Creatomate 세로형 템플릿 ID",
    )
    TEMPLATE_DURATION_VERTICAL: float = Field(
        default=90.0,
        description="세로형 템플릿 기본 duration (초)",
    )

    # 가로형 템플릿
    TEMPLATE_ID_HORIZONTAL: str = Field(
        default="0f092a6a-f526-4ef0-9181-d4ad4426b9e7",
        description="Creatomate 가로형 템플릿 ID",
    )
    TEMPLATE_DURATION_HORIZONTAL: float = Field(
        default=30.0,
        description="가로형 템플릿 기본 duration (초)",
    )

    model_config = _base_config


class KakaoSettings(BaseSettings):
    """카카오 OAuth 설정"""

    KAKAO_CLIENT_ID: str = Field(default="", description="카카오 REST API 키")
    KAKAO_CLIENT_SECRET: str = Field(default="", description="카카오 Client Secret (선택)")
    KAKAO_REDIRECT_URI: str = Field(
        default="http://localhost:8000/api/v1/user/auth/kakao/callback",
        description="카카오 로그인 후 리다이렉트 URI",
    )

    model_config = _base_config


class JWTSettings(BaseSettings):
    """JWT 토큰 설정"""

    JWT_SECRET: str = Field(
        default="your-super-secret-key-must-be-at-least-32-characters-long",
        description="JWT 서명 비밀키 (최소 32자)",
    )
    JWT_ALGORITHM: str = Field(default="HS256", description="JWT 알고리즘")
    JWT_ACCESS_TOKEN_EXPIRE_MINUTES: int = Field(
        default=60, description="액세스 토큰 만료 시간 (분)"
    )
    JWT_REFRESH_TOKEN_EXPIRE_DAYS: int = Field(
        default=7, description="리프레시 토큰 만료 시간 (일)"
    )

    model_config = _base_config


class LogSettings(BaseSettings):
    """
    로깅 설정 클래스

    애플리케이션의 로깅 동작을 제어하는 설정들을 관리합니다.
    모든 설정은 .env 파일 또는 환경변수로 오버라이드 가능합니다.

    사용 예시 (.env 파일):
        LOG_LEVEL=INFO
        LOG_CONSOLE_LEVEL=WARNING
        LOG_FILE_LEVEL=DEBUG
        LOG_DIR=/var/log/myapp
    """

    # ============================================================
    # 로그 디렉토리 설정
    # ============================================================
    # 로그 파일이 저장될 디렉토리 경로입니다.
    # - 기본값: 프로젝트 루트의 logs 폴더
    # - 운영 환경에서는 /www/log/uvicorn 또는 /var/log/app 등으로 설정 권장
    # - 디렉토리가 존재하지 않으면 자동으로 생성됩니다.
    # - .env 파일에서 LOG_DIR 환경변수로 오버라이드 가능
    LOG_DIR: str = Field(
        default="logs",
        description="로그 파일 저장 디렉토리 (절대 경로 또는 상대 경로)",
    )

    # ============================================================
    # 로그 출력 대상 설정
    # ============================================================
    # 콘솔 출력 활성화 여부
    # - True: 터미널/콘솔에 로그 출력
    # - False: 콘솔 출력 비활성화 (파일에만 기록)
    LOG_CONSOLE_ENABLED: bool = Field(
        default=True,
        description="콘솔 로그 출력 활성화 여부",
    )

    # 파일 출력 활성화 여부
    # - True: 로그 파일에 기록 (app.log, error.log)
    # - False: 파일 출력 비활성화 (콘솔에만 출력)
    LOG_FILE_ENABLED: bool = Field(
        default=True,
        description="파일 로그 출력 활성화 여부",
    )

    # ============================================================
    # 로그 레벨 설정
    # ============================================================
    # 로그 레벨 우선순위 (낮음 → 높음):
    #   DEBUG < INFO < WARNING < ERROR < CRITICAL
    #
    # 설정된 레벨 이상의 로그만 출력됩니다.
    # 예: INFO로 설정 시 DEBUG는 무시되고, INFO, WARNING, ERROR, CRITICAL만 출력
    # ============================================================

    # 기본 로그 레벨
    # - 로거 자체의 최소 로그 레벨을 설정합니다.
    # - 이 레벨보다 낮은 로그는 핸들러(콘솔/파일)로 전달되지 않습니다.
    # - 가능한 값: DEBUG, INFO, WARNING, ERROR, CRITICAL
    # - DEBUG: 개발 시 상세 디버깅 정보 (변수 값, 흐름 추적 등)
    # - INFO: 일반적인 작업 진행 상황 (요청 시작/완료 등)
    # - WARNING: 잠재적 문제 또는 주의가 필요한 상황
    # - ERROR: 오류 발생, 하지만 애플리케이션은 계속 실행
    # - CRITICAL: 심각한 오류, 애플리케이션 중단 가능성
    LOG_LEVEL: str = Field(
        default="DEBUG",
        description="기본 로그 레벨",
    )

    # 콘솔 출력 로그 레벨
    # - 터미널/콘솔에 출력되는 로그의 최소 레벨을 설정합니다.
    # - 개발 환경: DEBUG 권장 (모든 로그 확인)
    # - 운영 환경: INFO 또는 WARNING 권장 (중요한 정보만 출력)
    # - LOG_LEVEL보다 낮게 설정해도 LOG_LEVEL이 우선 적용됩니다.
    LOG_CONSOLE_LEVEL: str = Field(
        default="DEBUG",
        description="콘솔 출력 로그 레벨",
    )

    # 파일 출력 로그 레벨
    # - 로그 파일에 기록되는 로그의 최소 레벨을 설정합니다.
    # - 파일에는 더 상세한 로그를 남기고 싶을 때 DEBUG로 설정
    # - 파일 저장 위치: logs/{날짜}_{모듈명}.log
    # - 에러 로그는 별도로 logs/{날짜}_error.log에도 기록됩니다.
    LOG_FILE_LEVEL: str = Field(
        default="DEBUG",
        description="파일 출력 로그 레벨",
    )

    # ============================================================
    # 로그 파일 관리 설정
    # ============================================================

    # 로그 파일 최대 크기 (MB)
    # - 파일이 이 크기를 초과하면 자동으로 새 파일로 롤오버됩니다.
    # - 기존 파일은 .1, .2 등의 접미사가 붙어 백업됩니다.
    # - 예: 15MB 설정 시, 파일이 15MB를 넘으면 새 파일 생성
    LOG_MAX_SIZE_MB: int = Field(
        default=15,
        description="로그 파일 최대 크기 (MB)",
    )

    # 로그 파일 백업 개수
    # - 롤오버 시 보관할 백업 파일의 최대 개수입니다.
    # - 이 개수를 초과하면 가장 오래된 백업 파일이 삭제됩니다.
    # - 예: 30 설정 시, 최대 30개의 백업 파일 유지
    # - 디스크 용량 관리를 위해 적절한 값 설정 권장
    LOG_BACKUP_COUNT: int = Field(
        default=30,
        description="로그 파일 백업 개수",
    )

    # ============================================================
    # 로그 포맷 설정
    # ============================================================
    # 사용 가능한 포맷 변수:
    #   {asctime}   - 로그 발생 시간 (LOG_DATE_FORMAT 형식)
    #   {levelname} - 로그 레벨 (DEBUG, INFO 등)
    #   {name}      - 로거 이름 (home, song 등)
    #   {filename}  - 소스 파일명
    #   {funcName}  - 함수명
    #   {lineno}    - 라인 번호
    #   {message}   - 로그 메시지
    #   {module}    - 모듈명
    #   {pathname}  - 파일 전체 경로
    #
    # 포맷 예시:
    #   "[{asctime}] {levelname} {message}"
    #   출력: [2024-01-14 15:30:00] INFO 서버 시작
    # ============================================================

    # 콘솔 로그 포맷
    # - 터미널에 출력되는 로그의 형식을 지정합니다.
    # - [{levelname}]은 로그 레벨을 대괄호로 감싸서 출력합니다.
    LOG_CONSOLE_FORMAT: str = Field(
        default="[{asctime}] [{levelname}] [{name}:{funcName}:{lineno}] {message}",
        description="콘솔 로그 포맷",
    )

    # 파일 로그 포맷
    # - 파일에 기록되는 로그의 형식을 지정합니다.
    # - 파일에는 더 상세한 정보(filename 등)를 포함할 수 있습니다.
    LOG_FILE_FORMAT: str = Field(
        default="[{asctime}] [{levelname}] [{filename}:{name} -> {funcName}():{lineno}] {message}",
        description="파일 로그 포맷",
    )

    # 날짜 포맷
    # - {asctime}에 표시되는 시간의 형식을 지정합니다.
    # - Python strftime 형식을 따릅니다.
    # - 예시:
    #   "%Y-%m-%d %H:%M:%S"     -> 2024-01-14 15:30:00
    #   "%Y/%m/%d %H:%M:%S.%f"  -> 2024/01/14 15:30:00.123456
    #   "%d-%b-%Y %H:%M:%S"     -> 14-Jan-2024 15:30:00
    LOG_DATE_FORMAT: str = Field(
        default="%Y-%m-%d %H:%M:%S",
        description="로그 날짜 포맷",
    )

    model_config = _base_config

    def get_log_dir(self) -> Path:
        """
        로그 디렉토리 경로를 반환합니다.

        우선순위:
        1. .env의 LOG_DIR 설정값 (절대 경로인 경우)
        2. /www/log/uvicorn 폴더가 존재하면 사용 (운영 서버)
        3. 프로젝트 루트의 logs 폴더 (개발 환경 기본값)

        Returns:
            Path: 로그 디렉토리 경로 (존재하지 않으면 자동 생성)
        """
        # 1. .env에서 설정한 경로가 절대 경로인 경우 우선 사용
        log_dir_path = Path(self.LOG_DIR)
        if log_dir_path.is_absolute():
            log_dir_path.mkdir(parents=True, exist_ok=True)
            return log_dir_path

        # 2. 운영 서버 경로 확인 (/www/log/uvicorn)
        production_log_dir = Path("/www/log/uvicorn")
        if production_log_dir.exists():
            return production_log_dir

        # 3. 기본값: 프로젝트 루트의 logs 폴더
        default_log_dir = PROJECT_DIR / self.LOG_DIR
        default_log_dir.mkdir(parents=True, exist_ok=True)
        return default_log_dir


prj_settings = ProjectSettings()
apikey_settings = APIKeySettings()
db_settings = DatabaseSettings()
cors_settings = CORSSettings()
crawler_settings = CrawlerSettings()
azure_blob_settings = AzureBlobSettings()
creatomate_settings = CreatomateSettings()
log_settings = LogSettings()
kakao_settings = KakaoSettings()
jwt_settings = JWTSettings()
