
from __future__ import annotations

from fastapi import APIRouter, Depends, HTTPException, Query
from fastapi.responses import Response
from sqlalchemy.orm import Session

from app.core.db.deps import get_common_db
from app.core.security.session_auth import require_login
from app.modules.clients.access import ClientAccessScope, enforce_partner_scope, is_partner_role
from app.modules.clients.schemas import ClientAuditLogOut, ClientFilterOptions, ClientListResponse, ClientOut, ClientUpdate, ClientCreate
from app.modules.clients.service import (
    activate_client_service,
    archive_client_service,
    create_client_service,
    deactivate_client_service,
    export_clients_csv,
    get_client_or_404,
    get_filter_options,
    list_client_audit_logs,
    list_clients_payload,
    restore_client_service,
    update_client_service,
)
from app.modules.core.rbac.permission_guard import require_permission
from app.modules.core.rbac.deps import get_user_roles

router = APIRouter(prefix="/api/v1/clients", tags=["clients-api"])

def _api_scope_from_user(db, user):
    def has(code: str):
        try:
            require_permission(db, user, code)
            return True
        except Exception:
            return False
    own_only = has("clients.view.own_only") or not has("clients.assign_partner")
    scope = ClientAccessScope(
        tenant_id=user.tenant_id,
        branch_id=user.branch_id,
        allow_cross_branch=has("clients.cross_branch"),
        allow_cross_tenant=has("clients.cross_tenant"),
        allow_all_clients=has("clients.view.all") and not own_only,
        own_only=own_only,
        locked_partner_id=user.id if own_only else None,
        can_assign_partner=has("clients.assign_partner"),
        can_change_branch=has("clients.cross_branch"),
        can_change_tenant=has("clients.cross_tenant"),
    )
    return enforce_partner_scope(scope, user=user, role_names=get_user_roles(db, user.id))

@router.get("/filters", response_model=ClientFilterOptions)
def api_client_filters():
    return get_filter_options()

@router.get("", response_model=ClientListResponse)
def api_list_clients(
    q: str = Query("", max_length=100),
    status: str = Query("", max_length=20),
    client_type: str = Query("", max_length=100),
    partner_id: int | None = Query(None),
    include_archived: bool = Query(False),
    page: int = Query(1, ge=1),
    per_page: int = Query(10, ge=1, le=100),
    sort_by: str = Query("client_name"),
    sort_order: str = Query("asc"),
    db: Session = Depends(get_common_db),
    user=Depends(require_login),
):
    require_permission(db, user, "clients.view")
    scope = _api_scope_from_user(db, user)
    if scope.own_only:
        partner_id = scope.locked_partner_id
    return list_clients_payload(
        db,
        tenant_id=scope.tenant_id,
        branch_id=scope.branch_id,
        allow_cross_branch=scope.allow_cross_branch,
        partner_id=None if scope.own_only else partner_id,
        viewer_partner_id=user.id if scope.own_only else None,
        q=q,
        status=status,
        client_type=client_type,
        include_archived=include_archived,
        page=page,
        per_page=per_page,
        sort_by=sort_by,
        sort_order=sort_order,
    )

@router.get("/export")
def api_export_clients(
    q: str = Query("", max_length=100),
    status: str = Query("", max_length=20),
    client_type: str = Query("", max_length=100),
    partner_id: int | None = Query(None),
    include_archived: bool = Query(False),
    sort_by: str = Query("client_name"),
    sort_order: str = Query("asc"),
    db: Session = Depends(get_common_db),
    user=Depends(require_login),
):
    require_permission(db, user, "clients.export")
    scope = _api_scope_from_user(db, user)
    if scope.own_only:
        partner_id = scope.locked_partner_id
    payload = list_clients_payload(
        db,
        tenant_id=scope.tenant_id,
        branch_id=scope.branch_id,
        allow_cross_branch=scope.allow_cross_branch,
        partner_id=None if scope.own_only else partner_id,
        viewer_partner_id=user.id if scope.own_only else None,
        q=q,
        status=status,
        client_type=client_type,
        include_archived=include_archived,
        page=1,
        per_page=10000,
        sort_by=sort_by,
        sort_order=sort_order,
    )
    csv_text = export_clients_csv(payload)
    return Response(content=csv_text, media_type="text/csv", headers={"Content-Disposition": "attachment; filename=clients_export.csv"})

@router.get("/{client_id}", response_model=ClientOut)
def api_get_client(client_id: int, db: Session = Depends(get_common_db), user=Depends(require_login)):
    require_permission(db, user, "clients.view")
    scope = _api_scope_from_user(db, user)
    row = get_client_or_404(db, client_id=client_id, tenant_id=scope.tenant_id, branch_id=scope.branch_id, allow_cross_branch=scope.allow_cross_branch, allow_all_clients=scope.allow_all_clients, viewer_partner_id=user.id if scope.own_only else None, allow_review_access=True)
    return row

@router.post("", response_model=ClientOut, status_code=201)
def api_create_client(data: ClientCreate, db: Session = Depends(get_common_db), user=Depends(require_login)):
    require_permission(db, user, "clients.create")
    scope = _api_scope_from_user(db, user)
    return create_client_service(db, data=data, actor_user_id=user.id, scope=scope)

@router.put("/{client_id}", response_model=ClientOut)
def api_update_client(client_id: int, data: ClientUpdate, db: Session = Depends(get_common_db), user=Depends(require_login)):
    require_permission(db, user, "clients.edit")
    scope = _api_scope_from_user(db, user)
    row = get_client_or_404(db, client_id=client_id, tenant_id=scope.tenant_id, branch_id=scope.branch_id, allow_cross_branch=scope.allow_cross_branch, allow_all_clients=scope.allow_all_clients, viewer_partner_id=user.id if scope.own_only else None)
    if scope.own_only and row.partner_id != scope.locked_partner_id:
        raise HTTPException(status_code=404, detail="Client not found.")
    return update_client_service(db, row=row, data=data, actor_user_id=user.id, scope=scope)

@router.post("/{client_id}/deactivate", response_model=ClientOut)
def api_deactivate_client(client_id: int, db: Session = Depends(get_common_db), user=Depends(require_login)):
    require_permission(db, user, "clients.deactivate")
    scope = _api_scope_from_user(db, user)
    row = get_client_or_404(db, client_id=client_id, tenant_id=scope.tenant_id, branch_id=scope.branch_id, allow_cross_branch=scope.allow_cross_branch, allow_all_clients=scope.allow_all_clients, viewer_partner_id=user.id if scope.own_only else None)
    return deactivate_client_service(db, row=row, actor_user_id=user.id)

@router.post("/{client_id}/activate", response_model=ClientOut)
def api_activate_client(client_id: int, db: Session = Depends(get_common_db), user=Depends(require_login)):
    require_permission(db, user, "clients.activate")
    scope = _api_scope_from_user(db, user)
    row = get_client_or_404(db, client_id=client_id, tenant_id=scope.tenant_id, branch_id=scope.branch_id, allow_cross_branch=scope.allow_cross_branch, allow_all_clients=scope.allow_all_clients, viewer_partner_id=user.id if scope.own_only else None)
    return activate_client_service(db, row=row, actor_user_id=user.id)

@router.post("/{client_id}/archive", response_model=ClientOut)
def api_archive_client(client_id: int, db: Session = Depends(get_common_db), user=Depends(require_login)):
    require_permission(db, user, "clients.archive")
    scope = _api_scope_from_user(db, user)
    row = get_client_or_404(db, client_id=client_id, tenant_id=scope.tenant_id, branch_id=scope.branch_id, allow_cross_branch=scope.allow_cross_branch, allow_all_clients=scope.allow_all_clients, viewer_partner_id=user.id if scope.own_only else None)
    return archive_client_service(db, row=row, actor_user_id=user.id)

@router.post("/{client_id}/restore", response_model=ClientOut)
def api_restore_client(client_id: int, db: Session = Depends(get_common_db), user=Depends(require_login)):
    require_permission(db, user, "clients.restore")
    scope = _api_scope_from_user(db, user)
    row = get_client_or_404(db, client_id=client_id, tenant_id=scope.tenant_id, branch_id=scope.branch_id, allow_cross_branch=scope.allow_cross_branch, allow_all_clients=scope.allow_all_clients, viewer_partner_id=user.id if scope.own_only else None)
    return restore_client_service(db, row=row, actor_user_id=user.id)

@router.get("/{client_id}/audit-logs", response_model=list[ClientAuditLogOut])
def api_client_audit_logs(client_id: int, limit: int = Query(50, ge=1, le=200), db: Session = Depends(get_common_db), user=Depends(require_login)):
    require_permission(db, user, "clients.audit_log.view")
    scope = _api_scope_from_user(db, user)
    row = get_client_or_404(db, client_id=client_id, tenant_id=scope.tenant_id, branch_id=scope.branch_id, allow_cross_branch=scope.allow_cross_branch, allow_all_clients=scope.allow_all_clients, viewer_partner_id=user.id if scope.own_only else None)
    return list_client_audit_logs(db, row=row, limit=limit)
