"""
CSRF Protection Module (Phase 20)
=================================
Phase 19 首席架構師審查: 核鑰 UX 缺 CSRF 防護 (9/10)

實作模式: Double Submit Cookie
- 後端生成 CSRF Token，設定在 Cookie 中
- 前端在敏感請求 Header 中帶上相同 Token
- 後端驗證 Cookie 和 Header 的 Token 是否匹配

保護端點:
- POST /api/v1/approvals/{id}/sign   - 核鑰簽核
- POST /api/v1/approvals/{id}/reject - 拒絕請求
- POST /api/v1/approvals/bulk        - 批次處理

建立日期: 2026-03-28 (台北時間)
建立者: Claude Code (首席架構師)
"""

import secrets
from typing import Annotated

from fastapi import Cookie, Depends, Header, HTTPException, Request, Response, status

from src.core.config import settings
from src.core.logging import get_logger

logger = get_logger("awoooi.csrf")

# =============================================================================
# Constants
# =============================================================================

CSRF_COOKIE_NAME = "awoooi_csrf_token"
CSRF_HEADER_NAME = "X-CSRF-Token"
CSRF_TOKEN_LENGTH = 32  # 256 bits of entropy


# =============================================================================
# Token Generation
# =============================================================================


def generate_csrf_token() -> str:
    """
    生成加密安全的 CSRF Token

    Returns:
        str: 64 字元的十六進位 Token (32 bytes = 256 bits)
    """
    return secrets.token_hex(CSRF_TOKEN_LENGTH)


# =============================================================================
# Token Verification (Dependency Injection)
# =============================================================================


async def verify_csrf_token(
    request: Request,
    x_csrf_token: Annotated[str | None, Header(alias=CSRF_HEADER_NAME)] = None,
    csrf_cookie: Annotated[str | None, Cookie(alias=CSRF_COOKIE_NAME)] = None,
) -> str:
    """
    驗證 CSRF Token (FastAPI Depends)

    Double Submit Cookie 模式:
    1. 從 Cookie 取得 Token
    2. 從 Header 取得 Token
    3. 比對兩者是否一致

    Args:
        request: FastAPI Request 物件
        x_csrf_token: X-CSRF-Token Header
        csrf_cookie: awoooi_csrf_token Cookie

    Returns:
        str: 驗證通過的 CSRF Token

    Raises:
        HTTPException: 403 CSRF 驗證失敗
    """
    # 開發環境可選擇性跳過 CSRF 驗證 (不建議用於生產)
    if settings.ENVIRONMENT == "development" and settings.DEBUG:
        # 即使在開發環境也記錄警告
        if not csrf_cookie or not x_csrf_token:
            logger.warning(
                "csrf_skipped_dev_mode",
                has_cookie=bool(csrf_cookie),
                has_header=bool(x_csrf_token),
                path=request.url.path,
            )
            return "dev-mode-bypass"

    # 生產環境: 嚴格驗證
    if not csrf_cookie:
        logger.warning(
            "csrf_cookie_missing",
            path=request.url.path,
            client_ip=request.client.host if request.client else "unknown",
        )
        raise HTTPException(
            status_code=status.HTTP_403_FORBIDDEN,
            detail="CSRF token cookie missing. Please refresh the page.",
        )

    if not x_csrf_token:
        logger.warning(
            "csrf_header_missing",
            path=request.url.path,
            client_ip=request.client.host if request.client else "unknown",
        )
        raise HTTPException(
            status_code=status.HTTP_403_FORBIDDEN,
            detail="CSRF token header missing. Ensure X-CSRF-Token header is sent.",
        )

    # 時序安全比較 (防止 timing attack)
    if not secrets.compare_digest(csrf_cookie, x_csrf_token):
        logger.error(
            "csrf_token_mismatch",
            path=request.url.path,
            client_ip=request.client.host if request.client else "unknown",
        )
        raise HTTPException(
            status_code=status.HTTP_403_FORBIDDEN,
            detail="CSRF token validation failed. Please refresh the page and try again.",
        )

    logger.debug(
        "csrf_token_verified",
        path=request.url.path,
    )

    return csrf_cookie


# =============================================================================
# Response Helper
# =============================================================================


def set_csrf_cookie(response: Response, token: str | None = None) -> str:
    """
    在 Response 中設定 CSRF Cookie

    Args:
        response: FastAPI Response 物件
        token: 指定的 Token (None 時自動生成)

    Returns:
        str: 設定的 CSRF Token
    """
    csrf_token = token or generate_csrf_token()

    response.set_cookie(
        key=CSRF_COOKIE_NAME,
        value=csrf_token,
        httponly=False,  # 前端 JS 需要讀取
        secure=settings.ENVIRONMENT == "production",  # 生產環境啟用 HTTPS Only
        samesite="strict",  # 嚴格同站策略
        max_age=3600,  # 1 小時有效
        path="/",
    )

    logger.debug(
        "csrf_cookie_set",
        token_preview=csrf_token[:8] + "...",
    )

    return csrf_token


# =============================================================================
# Type Alias for Dependency Injection
# =============================================================================

CSRFToken = Annotated[str, Depends(verify_csrf_token)]
