"""Auth routes — login, logout, me, switch-tenant, password reset."""

from __future__ import annotations

import uuid

from fastapi import APIRouter, Depends, HTTPException, Request, Response, status
from sqlalchemy.ext.asyncio import AsyncSession

from app.config import get_settings
from app.core.auth import get_redis
from app.core.db import get_db
from app.core.rate_limit import check_rate_limit, get_client_ip, reset_rate_limit
from app.schemas.auth import (
    AuthResponse,
    LoginRequest,
    MessageResponse,
    PasswordResetConfirm,
    PasswordResetRequest,
    SwitchTenantRequest,
)
from app.deps import get_current_user
from app.services.auth_service import auth_service

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


@router.post("/login", response_model=AuthResponse)
async def login(
    request: Request,
    body: LoginRequest,
    db: AsyncSession = Depends(get_db),
):
    """Login with email+password. Sets session cookie."""
    ip = get_client_ip(request)
    redis = get_redis()

    # Rate limit
    await check_rate_limit(
        f"auth:login:{ip}:{body.email}",
        settings.rate_limit_login_max,
        settings.rate_limit_login_window,
    )

    result = await auth_service.login(db, redis, body.email, body.password)
    if result is None:
        raise HTTPException(
            status_code=status.HTTP_401_UNAUTHORIZED,
            detail={"detail": "Invalid email or password", "code": "invalid_credentials"},
        )

    session_id, csrf_token, user, tenant = result

    # Reset rate limit on success
    await reset_rate_limit(f"auth:login:{ip}:{body.email}")

    response = Response(status_code=status.HTTP_200_OK)
    response.set_cookie(
        key=settings.session_cookie_name,
        value=session_id,
        httponly=settings.session_cookie_httponly,
        secure=settings.session_cookie_secure,
        samesite=settings.session_cookie_samesite,
        max_age=settings.session_ttl_seconds,
        path="/",
    )
    # Return auth info in body
    from fastapi.responses import JSONResponse

    resp = JSONResponse(
        status_code=status.HTTP_200_OK,
        content={
            "user_id": str(user.id),
            "email": user.email,
            "name": user.name,
            "role": user.role,
            "is_system_admin": user.is_system_admin,
            "tenant_id": str(tenant.id),
            "tenant_name": tenant.name,
            "csrf_token": csrf_token,
        },
    )
    resp.set_cookie(
        key=settings.session_cookie_name,
        value=session_id,
        httponly=settings.session_cookie_httponly,
        secure=settings.session_cookie_secure,
        samesite=settings.session_cookie_samesite,
        max_age=settings.session_ttl_seconds,
        path="/",
    )
    return resp


@router.post("/logout", response_model=MessageResponse)
async def logout(
    request: Request,
    db: AsyncSession = Depends(get_db),
):
    """Logout — invalidate session, clear cookie."""
    session_id = request.cookies.get(settings.session_cookie_name)
    redis = get_redis()
    if session_id:
        await auth_service.logout(redis, session_id)

    from fastapi.responses import JSONResponse

    resp = JSONResponse(
        status_code=status.HTTP_200_OK,
        content={"message": "Logged out"},
    )
    resp.delete_cookie(settings.session_cookie_name, path="/")
    return resp


@router.get("/me", response_model=AuthResponse)
async def me(
    request: Request,
    db: AsyncSession = Depends(get_db),
):
    """Get current user + active tenant."""
    session_id = request.cookies.get(settings.session_cookie_name)
    if not session_id:
        raise HTTPException(
            status_code=status.HTTP_401_UNAUTHORIZED,
            detail={"detail": "Not authenticated", "code": "not_authenticated"},
        )

    redis = get_redis()
    info = await auth_service.get_current_user_info(db, redis, session_id)
    if info is None:
        raise HTTPException(
            status_code=status.HTTP_401_UNAUTHORIZED,
            detail={"detail": "Session expired or invalid", "code": "session_invalid"},
        )

    from fastapi.responses import JSONResponse
    resp = JSONResponse(status_code=200, content=info)
    resp.set_cookie(
        key=settings.session_cookie_name,
        value=session_id,
        httponly=settings.session_cookie_httponly,
        secure=settings.session_cookie_secure,
        samesite=settings.session_cookie_samesite,
        max_age=settings.session_ttl_seconds,
        path="/",
    )
    return resp


@router.get("/me/permissions")
async def me_permissions(
    request: Request,
    db: AsyncSession = Depends(get_db),
    current_user: dict = Depends(get_current_user),
):
    """Get resolved permissions for the current user.

    Returns permissions, denied_permissions, field_permissions, and is_system_admin.
    Used by frontend to enable/disable UI elements based on permissions.
    """
    return {
        "permissions": current_user.get("permissions", []),
        "denied_permissions": current_user.get("denied_permissions", []),
        "field_permissions": current_user.get("field_permissions", {}),
        "is_system_admin": current_user.get("is_system_admin", False),
    }


@router.post("/switch-tenant")
async def switch_tenant(
    request: Request,
    body: SwitchTenantRequest,
    db: AsyncSession = Depends(get_db),
):
    """Switch active tenant for current session."""
    session_id = request.cookies.get(settings.session_cookie_name)
    if not session_id:
        raise HTTPException(
            status_code=status.HTTP_401_UNAUTHORIZED,
            detail={"detail": "Not authenticated", "code": "not_authenticated"},
        )

    redis = get_redis()
    try:
        new_tenant_id = uuid.UUID(body.tenant_id)
    except ValueError:
        raise HTTPException(
            status_code=status.HTTP_400_BAD_REQUEST,
            detail={"detail": "Invalid tenant_id", "code": "invalid_tenant_id"},
        ) from None

    result = await auth_service.switch_tenant(db, redis, session_id, new_tenant_id)
    if result is None:
        raise HTTPException(
            status_code=status.HTTP_403_FORBIDDEN,
            detail={"detail": "Cannot switch to this tenant", "code": "tenant_switch_failed"},
        )

    return {
        "user_id": result["user_id"],
        "email": result["email"],
        "name": result["name"],
        "role": result["role"],
        "tenant_id": result["tenant_id"],
        "tenant_name": result.get("tenant_name"),
    }


@router.post("/password-reset/request")
async def password_reset_request(
    request: Request,
    body: PasswordResetRequest,
    db: AsyncSession = Depends(get_db),
):
    """Request password reset. Always returns 200 (no user enumeration)."""
    ip = get_client_ip(request)
    redis = get_redis()  # noqa: F841

    await check_rate_limit(
        f"auth:reset:{ip}",
        settings.rate_limit_reset_max,
        settings.rate_limit_reset_window,
    )

    await auth_service.request_password_reset(db, body.email)
    return {"message": "If the email exists, a reset link has been sent."}


@router.post("/password-reset/confirm")
async def password_reset_confirm(
    request: Request,
    body: PasswordResetConfirm,
    db: AsyncSession = Depends(get_db),
):
    """Reset password with a valid token."""
    ip = get_client_ip(request)
    redis = get_redis()  # noqa: F841

    await check_rate_limit(
        f"auth:reset_confirm:{ip}",
        settings.rate_limit_reset_confirm_max,
        settings.rate_limit_reset_confirm_window,
    )

    success = await auth_service.confirm_password_reset(db, body.token, body.new_password)
    if not success:
        raise HTTPException(
            status_code=status.HTTP_400_BAD_REQUEST,
            detail={"detail": "Invalid or expired token", "code": "invalid_token"},
        )

    return {"message": "Password has been reset successfully."}
