from __future__ import annotations

from typing import Annotated

from fastapi import APIRouter, Depends, HTTPException, Query, status
from sqlalchemy import func, or_, select
from sqlalchemy.orm import Session

from app.api.deps import CurrentUserContext, get_current_user, get_db
from app.models.employee import Employee
from app.models.financial_record import ExpenseClaim
from app.schemas.employee_profile import EmployeeProfileLatestRead
from app.services.account_behavior_profile import AccountBehaviorProfileService
from app.services.employee_behavior_profile_service import EmployeeBehaviorProfileService

router = APIRouter(prefix="/employee-profiles")
DbSession = Annotated[Session, Depends(get_db)]
CurrentUser = Annotated[CurrentUserContext, Depends(get_current_user)]


@router.get(
    "/me/latest",
    response_model=EmployeeProfileLatestRead,
    summary="读取当前登录人的最新用户画像",
    description="按当前登录用户的邮箱或姓名匹配员工目录，返回个人工作台使用的综合用户画像。",
)
def get_current_employee_latest_profile(
    db: DbSession,
    current_user: CurrentUser,
    scene: Annotated[str, Query(max_length=50)] = "operations",
    window_days: Annotated[int, Query(ge=1, le=365)] = 90,
    expense_type_scope: Annotated[str, Query(max_length=50)] = "overall",
) -> EmployeeProfileLatestRead:
    employee = _resolve_current_employee(db, current_user)
    if employee is None:
        return AccountBehaviorProfileService(
            db,
            tenant_id=current_user.tenant_id,
        ).get_latest_account_profile(
            account_id=current_user.username,
            account_name=current_user.name,
            identifiers=_current_account_identifiers(current_user),
            scene=scene,
            window_days=window_days,
            expense_type_scope=expense_type_scope,
        )

    service = EmployeeBehaviorProfileService(db, tenant_id=current_user.tenant_id)
    latest = service.get_latest_profile(
        employee_id=employee.id,
        scene=scene,
        window_days=window_days,
        expense_type_scope=expense_type_scope,
    )
    if latest.empty_reason or _missing_usage_duration_metric(latest):
        service.refresh_employee_profiles(
            employee_id=employee.id,
            window_days=(window_days,),
            expense_type_scope=expense_type_scope,
            source_task_type="workbench_on_demand",
        )
        latest = service.get_latest_profile(
            employee_id=employee.id,
            scene=scene,
            window_days=window_days,
            expense_type_scope=expense_type_scope,
        )
    return latest


@router.get(
    "/{target_employee_id}/latest",
    response_model=EmployeeProfileLatestRead,
    summary="读取员工最新业务行为画像",
    description="返回员工在指定场景下的最新画像快照，审批场景默认只展示费用支出和流程质量画像。",
)
def get_employee_latest_profile(
    target_employee_id: str,
    db: DbSession,
    current_user: CurrentUser,
    scene: Annotated[str, Query(max_length=50)] = "approval",
    claim_id: Annotated[str | None, Query(max_length=80)] = None,
    window_days: Annotated[int, Query(ge=1, le=365)] = 90,
    expense_type_scope: Annotated[str, Query(max_length=50)] = "overall",
) -> EmployeeProfileLatestRead:
    target = _resolve_tenant_employee(
        db,
        current_user.tenant_id,
        target_employee_id,
    )
    if target is None or not _can_read_target(db, current_user, target):
        _raise_not_found()
    if claim_id and not _claim_matches_target(
        db,
        tenant_id=current_user.tenant_id,
        claim_id=claim_id,
        employee_id=target.id,
    ):
        _raise_not_found()
    return EmployeeBehaviorProfileService(
        db,
        tenant_id=current_user.tenant_id,
    ).get_latest_profile(
        employee_id=target.id,
        scene=scene,
        claim_id=claim_id,
        window_days=window_days,
        expense_type_scope=expense_type_scope,
    )


def _resolve_current_employee(
    db: Session,
    current_user: CurrentUserContext,
) -> Employee | None:
    tenant_id = str(current_user.tenant_id or "").strip()
    if not tenant_id:
        return None
    identities = [
        str(current_user.employee_id or "").strip(),
        str(current_user.username or "").strip(),
        str(current_user.name or "").strip(),
    ]
    normalized = [item for item in dict.fromkeys(identities) if item]
    if not normalized:
        return None

    email_values = [item.lower() for item in normalized if "@" in item]
    exact_values = [item for item in normalized if "@" not in item]
    conditions = []

    if email_values:
        conditions.append(func.lower(Employee.email).in_(email_values))
    if exact_values:
        conditions.append(Employee.id.in_(exact_values))
        conditions.append(Employee.name.in_(exact_values))
        conditions.append(Employee.employee_no.in_(exact_values))

    if not conditions:
        return None

    stmt = (
        select(Employee)
        .where(
            Employee.tenant_id == tenant_id,
            or_(*conditions),
        )
        .order_by(Employee.created_at.asc())
        .limit(1)
    )
    return db.scalars(stmt).first()


def _resolve_tenant_employee(
    db: Session,
    tenant_id: str,
    identifier: str,
) -> Employee | None:
    normalized_tenant = str(tenant_id or "").strip()
    normalized = str(identifier or "").strip()
    if not normalized_tenant or not normalized:
        return None
    conditions = [
        Employee.id == normalized,
        Employee.employee_no == normalized,
        Employee.name == normalized,
    ]
    if "@" in normalized:
        conditions.append(func.lower(Employee.email) == normalized.lower())
    return db.scalars(
        select(Employee)
        .where(
            Employee.tenant_id == normalized_tenant,
            or_(*conditions),
        )
        .order_by(Employee.created_at.asc())
        .limit(1)
    ).first()


def _can_read_target(
    db: Session,
    current_user: CurrentUserContext,
    target: Employee,
) -> bool:
    current = _resolve_current_employee(db, current_user)
    if current is not None and current.id == target.id:
        return True
    role_codes = {str(item or "").strip().lower() for item in current_user.role_codes or []}
    if current_user.is_admin or role_codes & {"finance", "executive"}:
        return True
    return bool(
        current is not None
        and role_codes & {"manager", "approver"}
        and target.manager_id == current.id
    )


def _claim_matches_target(
    db: Session,
    *,
    tenant_id: str,
    claim_id: str,
    employee_id: str,
) -> bool:
    return bool(
        db.scalar(
            select(ExpenseClaim.id).where(
                ExpenseClaim.tenant_id == str(tenant_id or "").strip(),
                ExpenseClaim.id == str(claim_id or "").strip(),
                ExpenseClaim.employee_id == employee_id,
            )
        )
    )


def _raise_not_found() -> None:
    raise HTTPException(
        status_code=status.HTTP_404_NOT_FOUND,
        detail="员工画像不存在。",
    )


def _missing_usage_duration_metric(latest: EmployeeProfileLatestRead) -> bool:
    if latest.scene != "operations":
        return False

    for profile in latest.profiles:
        if profile.profile_type == "ai_usage":
            return "usage_duration_ms" not in profile.metrics
    return False


def _current_account_identifiers(current_user: CurrentUserContext) -> set[str]:
    return {
        item
        for item in (
            current_user.username,
            current_user.name,
        )
        if str(item or "").strip()
    }
