from typing import Annotated

from fastapi import APIRouter, Depends, File, HTTPException, Query, UploadFile
from fastapi.responses import StreamingResponse

from app.application.exceptions import ValidationError
from app.application.services.users_roles_service import UsersRolesService
from app.domain.entities.user_registration import UserRegistration
from app.domain.entities.users_roles import RolePermission
from app.domain.enums import CompanyUserStatus
from app.presentation.auth_dependencies import get_current_user
from app.presentation.company_dependencies import get_validated_company_id_query
from app.presentation.dependencies import get_users_roles_service
from app.presentation.schemas.common import DataTableResponse, MessageResponse
from app.presentation.schemas.users_roles import (
    CompanyUserCreate,
    CompanyUserResponse,
    CompanyUserUpdate,
    PermissionModuleMeta,
    RoleCreate,
    RoleResponse,
    RoleUpdate,
    UsersImportResponse,
    UsersRolesSummaryResponse,
)

router = APIRouter(prefix="/users-roles", tags=["Users & Roles"])

CompanyId = Annotated[str, Depends(get_validated_company_id_query)]


def _build_datatable(
    data: list, total: int, page: int, page_size: int
) -> DataTableResponse:
    return DataTableResponse(
        data=data,
        total=total,
        page=page,
        page_size=page_size,
        total_pages=max(1, (total + page_size - 1) // page_size) if page_size else 1,
    )


@router.get(
    "/modules",
    response_model=list[PermissionModuleMeta],
    summary="Permission modules",
)
async def list_permission_modules(
    company_id: CompanyId,
    current_user: UserRegistration = Depends(get_current_user),
    service: UsersRolesService = Depends(get_users_roles_service),
):
    modules = await service.list_permission_modules_for_company(current_user, company_id)
    return [PermissionModuleMeta.model_validate(m) for m in modules]


@router.get(
    "/summary",
    response_model=UsersRolesSummaryResponse,
    summary="Users & Roles dashboard summary",
)
async def get_summary(
    company_id: CompanyId,
    current_user: UserRegistration = Depends(get_current_user),
    service: UsersRolesService = Depends(get_users_roles_service),
):
    """KPI cards: Total Users, Active Users, Disabled Users, Total Roles."""
    summary = await service.get_summary(current_user, company_id)
    return UsersRolesSummaryResponse.model_validate(
        summary.model_dump() if hasattr(summary, "model_dump") else summary
    )


@router.get("/roles", response_model=DataTableResponse[RoleResponse], summary="List roles")
async def list_roles(
    company_id: CompanyId,
    search: str | None = None,
    page: int = Query(1, ge=1),
    page_size: int = Query(100, ge=1, le=500),
    current_user: UserRegistration = Depends(get_current_user),
    service: UsersRolesService = Depends(get_users_roles_service),
):
    items, total = await service.list_roles(
        current_user, company_id, search=search, page=page, page_size=page_size
    )
    data = [
        RoleResponse.model_validate(i.model_dump() if hasattr(i, "model_dump") else i)
        for i in items
    ]
    return _build_datatable(data, total, page, page_size)


@router.post("/roles", response_model=RoleResponse, summary="Create role")
async def create_role(
    company_id: CompanyId,
    payload: RoleCreate,
    current_user: UserRegistration = Depends(get_current_user),
    service: UsersRolesService = Depends(get_users_roles_service),
):
    permissions = [
        RolePermission.model_validate(p.model_dump()) for p in payload.permissions
    ]
    role = await service.create_role(
        current_user,
        company_id,
        {
            "name": payload.name,
            "slug": payload.slug,
            "description": payload.description,
            "permissions": permissions,
        },
    )
    return RoleResponse.model_validate(
        role.model_dump() if hasattr(role, "model_dump") else role
    )


@router.get("/roles/{role_id}", response_model=RoleResponse, summary="Get role")
async def get_role(
    company_id: CompanyId,
    role_id: str,
    current_user: UserRegistration = Depends(get_current_user),
    service: UsersRolesService = Depends(get_users_roles_service),
):
    role = await service.get_role(current_user, company_id, role_id)
    return RoleResponse.model_validate(
        role.model_dump() if hasattr(role, "model_dump") else role
    )


@router.put("/roles/{role_id}", response_model=RoleResponse, summary="Update role")
async def update_role(
    company_id: CompanyId,
    role_id: str,
    payload: RoleUpdate,
    current_user: UserRegistration = Depends(get_current_user),
    service: UsersRolesService = Depends(get_users_roles_service),
):
    data = payload.model_dump(exclude_unset=True)
    if "permissions" in data and data["permissions"] is not None:
        data["permissions"] = [
            RolePermission.model_validate(p) for p in data["permissions"]
        ]
    role = await service.update_role(current_user, company_id, role_id, data)
    return RoleResponse.model_validate(
        role.model_dump() if hasattr(role, "model_dump") else role
    )


@router.delete("/roles/{role_id}", response_model=MessageResponse, summary="Delete role")
async def delete_role(
    company_id: CompanyId,
    role_id: str,
    current_user: UserRegistration = Depends(get_current_user),
    service: UsersRolesService = Depends(get_users_roles_service),
):
    await service.delete_role(current_user, company_id, role_id)
    return MessageResponse(message="Role deleted")


@router.get(
    "/users",
    response_model=DataTableResponse[CompanyUserResponse],
    summary="List users",
)
async def list_users(
    company_id: CompanyId,
    role_id: str | None = Query(None, description="Filter by role"),
    department_id: str | None = Query(None, description="Filter by department"),
    status: CompanyUserStatus | None = Query(
        None, description="Filter by status: active | disabled"
    ),
    search: str | None = Query(
        None, description="Search by name, email, username, or employee code"
    ),
    sort_by: str = Query(
        "full_name",
        description="full_name | email | status | last_login | created_at | employee_code | username",
    ),
    sort_dir: str = Query("asc", description="asc | desc"),
    page: int = Query(1, ge=1),
    page_size: int = Query(10, ge=1, le=200),
    current_user: UserRegistration = Depends(get_current_user),
    service: UsersRolesService = Depends(get_users_roles_service),
):
    items, total = await service.list_users(
        current_user,
        company_id,
        role_id=role_id,
        department_id=department_id,
        status=status,
        search=search,
        sort_by=sort_by,
        sort_dir=sort_dir,
        page=page,
        page_size=page_size,
    )
    data = [
        CompanyUserResponse.model_validate(
            i.model_dump() if hasattr(i, "model_dump") else i
        )
        for i in items
    ]
    return _build_datatable(data, total, page, page_size)


@router.get(
    "/users/export",
    summary="Export users CSV",
    response_class=StreamingResponse,
)
async def export_users(
    company_id: CompanyId,
    role_id: str | None = None,
    department_id: str | None = None,
    status: CompanyUserStatus | None = None,
    search: str | None = None,
    current_user: UserRegistration = Depends(get_current_user),
    service: UsersRolesService = Depends(get_users_roles_service),
):
    csv_text = await service.export_users_csv(
        current_user,
        company_id,
        role_id=role_id,
        department_id=department_id,
        status=status,
        search=search,
    )
    return StreamingResponse(
        iter([csv_text]),
        media_type="text/csv",
        headers={"Content-Disposition": "attachment; filename=users.csv"},
    )


@router.post(
    "/users/import",
    response_model=UsersImportResponse,
    summary="Import users CSV",
)
async def import_users(
    company_id: CompanyId,
    file: UploadFile = File(
        ...,
        description=(
            "CSV with columns: full_name, username, email, password, role_slug "
            "(optional: phone, employee_code, department_code, status, "
            "send_welcome_email, address, notes)"
        ),
    ),
    current_user: UserRegistration = Depends(get_current_user),
    service: UsersRolesService = Depends(get_users_roles_service),
):
    raw = await file.read()
    try:
        content = raw.decode("utf-8-sig")
    except UnicodeDecodeError as exc:
        raise HTTPException(status_code=400, detail="CSV must be UTF-8 encoded") from exc
    try:
        result = await service.import_users_csv(current_user, company_id, content)
    except ValidationError as exc:
        raise HTTPException(status_code=400, detail=str(exc)) from exc
    return UsersImportResponse.model_validate(result)


@router.post("/users", response_model=CompanyUserResponse, summary="Create user")
async def create_user(
    company_id: CompanyId,
    payload: CompanyUserCreate,
    current_user: UserRegistration = Depends(get_current_user),
    service: UsersRolesService = Depends(get_users_roles_service),
):
    user = await service.create_user(
        current_user, company_id, payload.model_dump()
    )
    return CompanyUserResponse.model_validate(
        user.model_dump() if hasattr(user, "model_dump") else user
    )


@router.get(
    "/users/{user_id}",
    response_model=CompanyUserResponse,
    summary="Get user",
)
async def get_user(
    company_id: CompanyId,
    user_id: str,
    current_user: UserRegistration = Depends(get_current_user),
    service: UsersRolesService = Depends(get_users_roles_service),
):
    user = await service.get_user(current_user, company_id, user_id)
    return CompanyUserResponse.model_validate(
        user.model_dump() if hasattr(user, "model_dump") else user
    )


@router.put(
    "/users/{user_id}",
    response_model=CompanyUserResponse,
    summary="Update user",
)
async def update_user(
    company_id: CompanyId,
    user_id: str,
    payload: CompanyUserUpdate,
    current_user: UserRegistration = Depends(get_current_user),
    service: UsersRolesService = Depends(get_users_roles_service),
):
    user = await service.update_user(
        current_user, company_id, user_id, payload.model_dump(exclude_unset=True)
    )
    return CompanyUserResponse.model_validate(
        user.model_dump() if hasattr(user, "model_dump") else user
    )


@router.delete(
    "/users/{user_id}",
    response_model=MessageResponse,
    summary="Delete user",
)
async def delete_user(
    company_id: CompanyId,
    user_id: str,
    current_user: UserRegistration = Depends(get_current_user),
    service: UsersRolesService = Depends(get_users_roles_service),
):
    await service.delete_user(current_user, company_id, user_id)
    return MessageResponse(message="User deleted")
