from typing import Annotated
from urllib.parse import urlparse

from fastapi import APIRouter, Form, HTTPException, Request
from fastapi.responses import HTMLResponse, RedirectResponse
from fastapi.templating import Jinja2Templates
from starlette import status

from app.auth import authenticate_user, create_access_token
from app.core.logging import bind_log_context, get_audit_logger, get_logger


router = APIRouter()
templates = Jinja2Templates(directory="web")
logger = get_logger(__name__)
audit_logger = get_audit_logger()


def _sanitize_next_path(next_path: str | None, default: str = "/dashboard") -> str:
    candidate = str(next_path or "").strip()
    if not candidate:
        return default

    parsed = urlparse(candidate)
    if parsed.scheme or parsed.netloc:
        return default
    if not candidate.startswith("/") or candidate.startswith("//"):
        return default
    if "\\" in candidate:
        return default
    if candidate.startswith("/login"):
        return default
    return candidate


@router.get("/login", response_class=HTMLResponse)
async def show_login_form(request: Request):
    next_path = _sanitize_next_path(request.query_params.get("next"), default="/dashboard")
    access_token = request.cookies.get("access_token")

    if access_token:
        try:
            from app.auth import get_current_user
            user = await get_current_user(access_token=access_token)
            if user:
                return RedirectResponse(url=next_path, status_code=status.HTTP_302_FOUND)
        except HTTPException:
            ...

    return templates.TemplateResponse(
        request,
        "login.html",
        {"request": request, "next_path": next_path},
    )

@router.post("/login")
async def login_post(
    request: Request,
    username: Annotated[str, Form(...)],
    password: Annotated[str, Form(...)],
    next_path: Annotated[str, Form(alias="next")] = "/dashboard",
):
    safe_next = _sanitize_next_path(next_path, default="/dashboard")
    user = await authenticate_user(username, password)
    if not user:
        audit_logger.business_event(
            event_type="auth.login_failure",
            action="login",
            outcome="warning",
            service="users_route",
            resource={"username": username},
        )
        # Vuelve a mostrar el login con error
        return templates.TemplateResponse(
            request,
            "login.html",
            {
                "request": request,
                "error": "Credenciales inválidas",
                "next_path": safe_next,
            },
        )

    token = create_access_token({"sub": user.username})
    bind_log_context(username=user.username)
    logger.info("Login successful for username=%s", user.username)
    audit_logger.business_event(
        event_type="auth.login_success",
        action="login",
        outcome="success",
        service="users_route",
        resource={"username": user.username},
    )
    response = RedirectResponse(url=safe_next, status_code=302)
    response.set_cookie(key="access_token", value=f"Bearer {token}", httponly=True)
    return response


@router.get("/logout")
async def logout(request: Request):
    username = getattr(request.state, "username", "") or ""
    if username:
        bind_log_context(username=username)
    logger.info("Logout request processed for username=%s", username or "anonymous")
    audit_logger.business_event(
        event_type="auth.logout",
        action="logout",
        outcome="success",
        service="users_route",
        resource={"username": username},
    )
    response = RedirectResponse(url="/login", status_code=status.HTTP_302_FOUND)
    response.delete_cookie("access_token")
    return response
