# Copyright (c) 2025 Patrick Motsch
# All rights reserved.
"""
JWT Service
Centralizes local JWT creation and cookie helpers.
"""

from datetime import timedelta
from typing import Optional, Tuple
from fastapi import Response
from jose import jwt

from modules.shared.configuration import APP_CONFIG
from modules.shared.timeUtils import getUtcNow

# Config
SECRET_KEY = APP_CONFIG.get("APP_JWT_KEY_SECRET")
ALGORITHM = APP_CONFIG.get("Auth_ALGORITHM")
ACCESS_TOKEN_EXPIRE_MINUTES = int(APP_CONFIG.get("APP_TOKEN_EXPIRY"))
REFRESH_TOKEN_EXPIRE_DAYS = int(APP_CONFIG.get("APP_REFRESH_TOKEN_EXPIRY", "7"))

# Cookie security settings - use secure cookies based on whether API uses HTTPS
# Cookies must have secure=True on HTTPS sites, secure=False on HTTP sites
APP_API_URL = APP_CONFIG.get("APP_API_URL", "http://localhost:8000")
USE_SECURE_COOKIES = APP_API_URL.startswith("https://") if APP_API_URL else False


def createAccessToken(data: dict, expiresDelta: Optional[timedelta] = None) -> Tuple[str, "datetime"]:
    """Create a JWT access token and return (token, expiresAt)."""
    toEncode = data.copy()
    if "jti" not in toEncode or not toEncode.get("jti"):
        import uuid
        toEncode["jti"] = str(uuid.uuid4())

    expire = getUtcNow() + (expiresDelta if expiresDelta else timedelta(minutes=ACCESS_TOKEN_EXPIRE_MINUTES))
    toEncode.update({"exp": expire})
    encodedJwt = jwt.encode(toEncode, SECRET_KEY, algorithm=ALGORITHM)
    return encodedJwt, expire


def createRefreshToken(data: dict) -> Tuple[str, "datetime"]:
    """Create a JWT refresh token and return (token, expiresAt)."""
    toEncode = data.copy()
    if "jti" not in toEncode or not toEncode.get("jti"):
        import uuid
        toEncode["jti"] = str(uuid.uuid4())
    toEncode["type"] = "refresh"

    expire = getUtcNow() + timedelta(days=REFRESH_TOKEN_EXPIRE_DAYS)
    toEncode.update({"exp": expire})
    encodedJwt = jwt.encode(toEncode, SECRET_KEY, algorithm=ALGORITHM)
    return encodedJwt, expire


def setAccessTokenCookie(response: Response, token: str, expiresDelta: Optional[timedelta] = None) -> None:
    """Set access token as httpOnly cookie."""
    maxAge = int(expiresDelta.total_seconds()) if expiresDelta else ACCESS_TOKEN_EXPIRE_MINUTES * 60
    response.set_cookie(
        key="auth_token",
        value=token,
        httponly=True,
        secure=USE_SECURE_COOKIES,  # Only secure in production (HTTPS)
        samesite="strict",
        path="/",
        max_age=maxAge
    )


def setRefreshTokenCookie(response: Response, token: str) -> None:
    """Set refresh token as httpOnly cookie."""
    response.set_cookie(
        key="refresh_token",
        value=token,
        httponly=True,
        secure=USE_SECURE_COOKIES,  # Only secure in production (HTTPS)
        samesite="strict",
        path="/",
        max_age=REFRESH_TOKEN_EXPIRE_DAYS * 24 * 60 * 60
    )


def clearAccessTokenCookie(response: Response) -> None:
    """
    Clear access token cookie by setting it to expire immediately.
    Uses both raw header manipulation and FastAPI's delete_cookie for maximum browser compatibility.
    """
    # Build secure flag based on environment
    secure_flag = "; Secure" if USE_SECURE_COOKIES else ""
    
    # Primary method: Raw Set-Cookie header for guaranteed deletion
    response.headers.append(
        "Set-Cookie",
        f"auth_token=deleted; Path=/; Max-Age=0; Expires=Thu, 01 Jan 1970 00:00:00 GMT; HttpOnly{secure_flag}; SameSite=Strict"
    )
    
    # Fallback: Also use FastAPI's built-in method
    response.delete_cookie(key="auth_token", path="/")


def clearRefreshTokenCookie(response: Response) -> None:
    """
    Clear refresh token cookie by setting it to expire immediately.
    Uses both raw header manipulation and FastAPI's delete_cookie for maximum browser compatibility.
    """
    # Build secure flag based on environment
    secure_flag = "; Secure" if USE_SECURE_COOKIES else ""
    
    # Primary method: Raw Set-Cookie header for guaranteed deletion
    response.headers.append(
        "Set-Cookie",
        f"refresh_token=deleted; Path=/; Max-Age=0; Expires=Thu, 01 Jan 1970 00:00:00 GMT; HttpOnly{secure_flag}; SameSite=Strict"
    )
    
    # Fallback: Also use FastAPI's built-in method
    response.delete_cookie(key="refresh_token", path="/")


