"""Authentication API endpoints for Enterprise Brain.

Provides login and token verification endpoints as Starlette handlers.
"""

from pydantic import BaseModel, ValidationError
from typing import Optional
from starlette.requests import Request
from starlette.responses import JSONResponse
from loguru import logger

from backend.chanakya.auth.database import get_user_by_username, upsert_user as db_upsert_user
from backend.chanakya.auth.utils import (
    verify_password,
    hash_password,
    create_access_token,
    decode_access_token,
)


# ---------------------------------------------------------------------------
# Request/Response models (for validation)
# ---------------------------------------------------------------------------

class LoginRequest(BaseModel):
    """Login request payload."""
    username: str
    password: str


class UpsertUserRequest(BaseModel):
    """Upsert user request payload."""
    id: int
    username: str
    password: str


# ---------------------------------------------------------------------------
# Authentication handlers (Starlette-compatible)
# ---------------------------------------------------------------------------

async def login(request: Request) -> JSONResponse:
    """POST /auth/login — authenticate and return JWT token."""
    try:
        body = await request.json()
        
        # Validate request
        try:
            credentials = LoginRequest(**body)
        except ValidationError as e:
            return JSONResponse(
                {"detail": "Invalid request body", "errors": e.errors()},
                status_code=400,
            )
        
        # Get user from database
        user = await get_user_by_username(credentials.username)

        if not user:
            return JSONResponse(
                {"detail": "Invalid username or password"},
                status_code=401,
            )

        # Check if account is active (deleted_at should be NULL)
        if not user.get("is_active"):
            return JSONResponse(
                {"detail": "Account is deactivated"},
                status_code=403,
            )

        # Verify password
        if not verify_password(credentials.password, user["hashed_password"]):
            return JSONResponse(
                {"detail": "Invalid username or password"},
                status_code=401,
            )

        # Create access token
        access_token = create_access_token(
            data={"sub": user["username"], "user_id": str(user["id"])}
        )

        return JSONResponse({
            "access_token": access_token,
            "token_type": "bearer",
            "username": user["username"],
            "user_id": str(user["id"]),
        })
        
    except Exception as exc:
        logger.error("Login error: {}", exc)
        return JSONResponse(
            {"detail": "Login failed"},
            status_code=500,
        )


async def verify_token(request: Request) -> JSONResponse:
    """POST /auth/verify-token — verify JWT token validity."""
    try:
        auth_header = request.headers.get("authorization", "")
        if not auth_header.startswith("Bearer "):
            return JSONResponse({"valid": False})
        
        token = auth_header.replace("Bearer ", "")
        payload = decode_access_token(token)
        
        if not payload:
            return JSONResponse({"valid": False})
        
        username = payload.get("sub")
        user_id = payload.get("user_id")
        
        # Verify user still exists and is active
        if username:
            user = await get_user_by_username(username)
            if user and user.get("is_active"):
                return JSONResponse({
                    "valid": True,
                    "username": username,
                    "user_id": user_id,
                })
        
        return JSONResponse({"valid": False})
        
    except Exception as exc:
        logger.error("Token verify error: {}", exc)
        return JSONResponse({"valid": False})


async def get_current_user(request: Request) -> JSONResponse:
    """GET /auth/me — get current user information."""
    try:
        auth_header = request.headers.get("authorization", "")
        if not auth_header.startswith("Bearer "):
            return JSONResponse(
                {"detail": "Missing authorization header"},
                status_code=401,
            )
        
        token = auth_header.replace("Bearer ", "")
        payload = decode_access_token(token)
        
        if not payload:
            return JSONResponse(
                {"detail": "Invalid or expired token"},
                status_code=401,
            )
        
        username = payload.get("sub")
        user = await get_user_by_username(username)
        
        if not user or not user.get("is_active"):
            return JSONResponse(
                {"detail": "User not found or inactive"},
                status_code=401,
            )
        
        # Remove sensitive data
        user_data = dict(user)
        user_data.pop("hashed_password", None)
        user_data.pop("deleted_at", None)
        
        return JSONResponse(user_data)
        
    except Exception as exc:
        logger.error("Get user error: {}", exc)
        return JSONResponse(
            {"detail": "Failed to get user"},
            status_code=500,
        )


async def upsert_user(request: Request) -> JSONResponse:
    """POST /auth/upsert-user — insert or update a user with a hashed password."""
    try:
        body = await request.json()

        try:
            payload = UpsertUserRequest(**body)
        except Exception as e:
            return JSONResponse(
                {"detail": "Invalid request body", "errors": str(e)},
                status_code=400,
            )

        hashed = hash_password(payload.password)
        action = await db_upsert_user(payload.id, payload.username, hashed)

        return JSONResponse(
            {"id": payload.id, "username": payload.username, "action": action},
            status_code=200,
        )

    except Exception as exc:
        logger.error("Upsert user error: {}", exc)
        return JSONResponse(
            {"detail": "Failed to upsert user"},
            status_code=500,
        )
