from fastapi import APIRouter, Depends, HTTPException, Request, Response, status
from slowapi import Limiter
from slowapi.util import get_remote_address
from sqlalchemy.ext.asyncio import AsyncSession

from app.core.config import settings

limiter = Limiter(key_func=get_remote_address)
from app.core.database import get_db
from app.core.security import verify_token
from app.dependencies import get_current_user
from app.models.user import User
from app.repositories import user_repository
from app.schemas.auth import LoginRequest, TokenResponse, UserAssignmentWithPermissions, UserResponse
from app.services import auth_service

router = APIRouter()

COOKIE_MAX_AGE_ACCESS = settings.ACCESS_TOKEN_EXPIRE_MINUTES * 60
COOKIE_MAX_AGE_REFRESH = settings.REFRESH_TOKEN_EXPIRE_DAYS * 86400


def _set_auth_cookies(response: Response, tokens: TokenResponse) -> None:
    response.set_cookie(
        key="access_token",
        value=tokens.access_token,
        httponly=True,
        secure=settings.is_production,
        samesite="lax",
        max_age=COOKIE_MAX_AGE_ACCESS,
    )
    response.set_cookie(
        key="refresh_token",
        value=tokens.refresh_token,
        httponly=True,
        secure=settings.is_production,
        samesite="lax",
        max_age=COOKIE_MAX_AGE_REFRESH,
    )


@router.post("/login")
@limiter.limit("10/minute")
async def login(
    request: Request,
    data: LoginRequest,
    response: Response,
    db: AsyncSession = Depends(get_db),
) -> dict:
    try:
        tokens = await auth_service.login(db, data.identifier, data.password)
    except ValueError as e:
        msg = str(e)
        if msg == "__MAINTENANCE__":
            raise HTTPException(
                status_code=status.HTTP_503_SERVICE_UNAVAILABLE,
                detail="MAINTENANCE_MODE",
            )
        raise HTTPException(status_code=status.HTTP_401_UNAUTHORIZED, detail=msg)
    _set_auth_cookies(response, tokens)
    payload = verify_token(tokens.access_token, token_type="access") or {}
    return {
        "message": "Login berhasil",
        "token_type": "cookie",
        "is_superadmin": bool(payload.get("is_superadmin", False)),
    }


@router.post("/refresh")
@limiter.limit("20/minute")
async def refresh(
    request: Request,
    response: Response,
    db: AsyncSession = Depends(get_db),
) -> dict:
    refresh_token = request.cookies.get("refresh_token")
    if not refresh_token:
        raise HTTPException(
            status_code=status.HTTP_401_UNAUTHORIZED,
            detail="Refresh token tidak ditemukan",
        )
    try:
        access_token = await auth_service.refresh_access_token(db, refresh_token)
    except ValueError as e:
        raise HTTPException(status_code=status.HTTP_401_UNAUTHORIZED, detail=str(e))
    response.set_cookie(
        key="access_token",
        value=access_token,
        httponly=True,
        secure=settings.is_production,
        samesite="lax",
        max_age=COOKIE_MAX_AGE_ACCESS,
    )
    return {"message": "Token diperbarui"}


@router.post("/logout")
async def logout(response: Response) -> dict:
    response.delete_cookie("access_token")
    response.delete_cookie("refresh_token")
    return {"message": "Logout berhasil"}


@router.get("/me", response_model=UserResponse)
async def me(
    current_user: User = Depends(get_current_user),
    db: AsyncSession = Depends(get_db),
) -> UserResponse:
    user = await user_repository.get_with_permissions(db, current_user.id)
    assignments = []
    for a in (user.assignments if user else []):
        role = a.role
        spbu = a.spbu
        assignments.append(UserAssignmentWithPermissions(
            spbu_id=a.spbu_id,
            spbu_name=spbu.name if spbu else "",
            role_id=a.role_id,
            role_name=role.nama if role else "",
            can_be_scheduled=role.can_be_scheduled if role else False,
            permissions=[
                f"{p.modul.value}:{p.aksi.value}"
                for p in (role.permissions if role else [])
            ],
        ))
    return UserResponse(
        id=current_user.id,
        name=current_user.name,
        email=current_user.email,
        is_superadmin=current_user.is_superadmin,
        is_active=current_user.is_active,
        assignments=assignments,
    )
