"""
JWT 토큰 유틸리티

Access Token과 Refresh Token의 생성, 검증, 해시 기능을 제공합니다.
"""

import hashlib
from datetime import datetime, timedelta, timezone
from typing import Optional

from jose import JWTError, jwt

from config import jwt_settings


def create_access_token(user_id: int) -> str:
    """
    JWT 액세스 토큰 생성

    Args:
        user_id: 사용자 ID

    Returns:
        JWT 액세스 토큰 문자열
    """
    expire = datetime.now(timezone.utc) + timedelta(
        minutes=jwt_settings.JWT_ACCESS_TOKEN_EXPIRE_MINUTES
    )
    to_encode = {
        "sub": str(user_id),
        "exp": expire,
        "type": "access",
    }
    return jwt.encode(
        to_encode,
        jwt_settings.JWT_SECRET,
        algorithm=jwt_settings.JWT_ALGORITHM,
    )


def create_refresh_token(user_id: int) -> str:
    """
    JWT 리프레시 토큰 생성

    Args:
        user_id: 사용자 ID

    Returns:
        JWT 리프레시 토큰 문자열
    """
    expire = datetime.now(timezone.utc) + timedelta(
        days=jwt_settings.JWT_REFRESH_TOKEN_EXPIRE_DAYS
    )
    to_encode = {
        "sub": str(user_id),
        "exp": expire,
        "type": "refresh",
    }
    return jwt.encode(
        to_encode,
        jwt_settings.JWT_SECRET,
        algorithm=jwt_settings.JWT_ALGORITHM,
    )


def decode_token(token: str) -> Optional[dict]:
    """
    JWT 토큰 디코딩

    Args:
        token: JWT 토큰 문자열

    Returns:
        디코딩된 페이로드 딕셔너리, 실패 시 None
    """
    try:
        payload = jwt.decode(
            token,
            jwt_settings.JWT_SECRET,
            algorithms=[jwt_settings.JWT_ALGORITHM],
        )
        return payload
    except JWTError:
        return None


def get_token_hash(token: str) -> str:
    """
    토큰의 SHA-256 해시값 생성

    리프레시 토큰을 DB에 저장할 때 원본 대신 해시값을 저장합니다.

    Args:
        token: 해시할 토큰 문자열

    Returns:
        토큰의 SHA-256 해시값 (64자 hex 문자열)
    """
    return hashlib.sha256(token.encode()).hexdigest()


def get_refresh_token_expires_at() -> datetime:
    """
    리프레시 토큰 만료 시간 계산

    Returns:
        리프레시 토큰 만료 datetime (UTC)
    """
    return datetime.now(timezone.utc) + timedelta(
        days=jwt_settings.JWT_REFRESH_TOKEN_EXPIRE_DAYS
    )


def get_access_token_expire_seconds() -> int:
    """
    액세스 토큰 만료 시간(초) 반환

    Returns:
        액세스 토큰 만료 시간 (초)
    """
    return jwt_settings.JWT_ACCESS_TOKEN_EXPIRE_MINUTES * 60
