"""
routes/auth.py
POST /api/auth/captcha/challenge        — generate math CAPTCHA
POST /api/auth/captcha/refresh          — get a fresh challenge
POST /api/auth/captcha/verify           — verify answer
POST /api/auth/login                    — access key → JWT
GET  /api/auth/me                       — current candidate info
"""
from __future__ import annotations

import json
import psycopg2
from fastapi import APIRouter, Depends, HTTPException, status
from pydantic import BaseModel

from models.schemas import (
    LoginRequest, LoginResponse, CandidateOut,
    CaptchaVerifyResponse, SuccessResponse,
)
from services.auth_service import (
    validate_access_key, create_token,
    get_redirect_url, get_stage_name,
)
from services.captcha_service import (
    create_challenge, refresh_challenge,
    verify_challenge, validate_captcha_token,
)
from middleware.auth_middleware import get_current_candidate
from utils.logger import get_logger

log = get_logger(__name__)

router = APIRouter(prefix="/api/auth", tags=["auth"])


# ── Helpers ───────────────────────────────────────────────────────────────────

def _pretty(data: dict | None) -> str:
    """Return a pretty-printed JSON string safe for logging.
    ensure_ascii=False so non-Latin scripts (Hindi etc.) print
    readably instead of as \\uXXXX escape sequences."""
    return json.dumps(data or {}, indent=2, default=str, ensure_ascii=False)


# ── Request models ────────────────────────────────────────────────────────────

class CaptchaVerifyRequest(BaseModel):
    session_id: str
    answer: str                 # math answer as string


class CaptchaRefreshRequest(BaseModel):
    session_id: str             # old session to invalidate


# ── CAPTCHA ──────────────────────────────────────────────────────────────────

@router.post("/captcha/challenge")
def captcha_challenge():
    """Generate a fresh math CAPTCHA challenge. Always called on page load."""
    log.info("POST /api/auth/captcha/challenge → generating new challenge")
    result = create_challenge()
    log.info("captcha/challenge response →\n%s", _pretty(result))
    return result


@router.post("/captcha/refresh")
def captcha_refresh(body: CaptchaRefreshRequest):
    """Invalidate the current challenge and return a new one."""
    log.info("POST /api/auth/captcha/refresh →\n%s", _pretty(body.model_dump()))
    result = refresh_challenge(body.session_id)
    log.info("captcha/refresh response →\n%s", _pretty(result))
    return result


@router.post("/captcha/verify")
def captcha_verify(body: CaptchaVerifyRequest):
    """Verify the candidate's math answer."""
    log.info("POST /api/auth/captcha/verify →\n%s", _pretty(body.model_dump()))
    result = verify_challenge(body.session_id, body.answer)
    log.info("captcha/verify response →\n%s", _pretty(
        result if isinstance(result, dict) else result.model_dump()
    ))
    return result


# ── Login ─────────────────────────────────────────────────────────────────────

@router.post("/login", response_model=LoginResponse)
def login(body: LoginRequest):
    """
    Validate access key + captcha token → return JWT + redirect URL.

    Flow:
      1. (Optional) verify CAPTCHA token.
      2. Look up `participant` row in PostgreSQL by UPPER(access_key).
      3. Mint JWT carrying { sub: candidate_id, name, stage }.
      4. Compute redirect URL from current_stage:
            1 → /people_hub_assessment
            2 → /people_hub_role_play
            3 → /people_hub_coding_assessment
    """
    log.info("POST /api/auth/login →\n%s", _pretty(body.model_dump()))

    # ── 1. CAPTCHA check ──────────────────────────────────────────────────────
    if body.captcha_token:
        if not validate_captcha_token(body.captcha_token):
            log.warning("login: CAPTCHA token invalid for access_key=%r", body.access_key)
            raise HTTPException(
                status_code=status.HTTP_400_BAD_REQUEST,
                detail="CAPTCHA verification failed or expired. Please verify again.",
            )
        log.info("login: CAPTCHA token OK")

    # ── 2. DB lookup ──────────────────────────────────────────────────────────
    try:
        candidate = validate_access_key(body.access_key)
    except (psycopg2.Error, RuntimeError) as exc:
        log.exception("login: DB error → %s", exc)
        raise HTTPException(
            status_code=status.HTTP_503_SERVICE_UNAVAILABLE,
            detail="Authentication service is temporarily unavailable. Please try again shortly.",
        )

    if not candidate:
        log.warning("login: no candidate found for access_key=%r", body.access_key)
        raise HTTPException(
            status_code=status.HTTP_401_UNAUTHORIZED,
            detail="Invalid or expired access key. Please check your email.",
        )

    log.info("login: candidate found →\n%s", _pretty({
        "id":            candidate.get("id"),
        "name":          candidate.get("name"),
        "email":         candidate.get("email"),
        "current_stage": candidate.get("current_stage"),
        "access_key":    candidate.get("access_key"),
    }))

    # ── 3. Mint JWT ───────────────────────────────────────────────────────────
    stage = int(candidate.get("current_stage") or 1)
    token = create_token(candidate["id"], candidate["name"], stage)

    redirect = get_redirect_url(stage)
    stage_name = get_stage_name(stage)

    log.info("login: JWT minted → stage=%d  redirect=%r  stage_name=%r",
             stage, redirect, stage_name)

    # ── 4. Build response ─────────────────────────────────────────────────────
    response = LoginResponse(
        token=token,
        token_type="bearer",
        candidate=CandidateOut(
            id=str(candidate.get("id", "")),
            name=str(candidate.get("name") or "Candidate"),
            email=str(candidate.get("email") or ""),
            phone=str(candidate.get("phone") or ""),
            skill_set=list(candidate.get("skill_set") or []),
            position_applied=str(candidate.get("position_applied") or ""),
            last_login=candidate.get("last_login"),
            last_question_attempt=candidate.get("last_question_attempt"),
            current_stage=stage,
            access_key=str(candidate.get("access_key") or ""),
        ),
        redirect_url=redirect,
        stage_name=stage_name,
    )

    log.info("login: response →\n%s", _pretty(response.model_dump()))
    return response


# ── Me ────────────────────────────────────────────────────────────────────────

@router.get("/me", response_model=SuccessResponse)
def me(candidate: dict = Depends(get_current_candidate)):
    """
    Return current candidate profile (used by HTML pages to populate
    the toolbar with the candidate name, current stage, etc.).
    """
    log.info("GET /api/auth/me →\n%s", _pretty({
        "id":            candidate.get("id"),
        "name":          candidate.get("name"),
        "current_stage": candidate.get("current_stage"),
    }))

    # Strip internal-only keys before returning
    safe = {k: v for k, v in candidate.items() if k != "_raw"}
    log.info("me: response →\n%s", _pretty(safe))
    return SuccessResponse(data=safe)