from __future__ import annotations

from datetime import UTC, datetime, timedelta
from decimal import Decimal
from typing import Any

from sqlalchemy import select
from sqlalchemy.orm import Session, selectinload

from app.algorithem.employee_behavior_profile import (
    LEVEL_LABELS,
    PROFILE_LABELS,
    ProfileComponent,
    evaluate_weighted_profile,
    score_by_bands,
)
from app.algorithem.employee_behavior_profile_tags import build_profile_radar, build_profile_tags
from app.models.agent_run import AgentRun
from app.schemas.employee_profile import EmployeeProfileLatestRead, EmployeeProfileRead
from app.services.employee_behavior_profile_helpers import EmployeeBehaviorProfileMetricHelpers
from app.services.finance_report_tenant import require_report_tenant_id


class AccountBehaviorProfileService(EmployeeBehaviorProfileMetricHelpers):
    def __init__(self, db: Session, *, tenant_id: str = "default") -> None:
        self.db = db
        self.tenant_id = require_report_tenant_id(tenant_id)

    def get_latest_account_profile(
        self,
        *,
        account_id: str,
        account_name: str,
        identifiers: set[str],
        scene: str,
        window_days: int,
        expense_type_scope: str,
    ) -> EmployeeProfileLatestRead:
        if scene != "operations":
            return EmployeeProfileLatestRead(
                employee_id=account_id,
                employee_name=account_name,
                scene=scene,
                window_days=window_days,
                expense_type_scope=expense_type_scope,
                empty_reason="当前账号未匹配员工目录，无法形成审批场景员工画像。",
            )

        cutoff = datetime.now(UTC) - timedelta(days=window_days)
        runs = self._fetch_account_runs(identifiers, cutoff)
        usage_duration_metrics = self._resolve_usage_duration_metrics(identifiers, cutoff, runs)
        if not runs and not usage_duration_metrics["online_duration_ms"]:
            return EmployeeProfileLatestRead(
                employee_id=account_id,
                employee_name=account_name,
                scene=scene,
                window_days=window_days,
                expense_type_scope=expense_type_scope,
                empty_reason="当前账号暂无可统计的智能体运行记录。",
            )

        result = self._calculate_account_ai_usage_profile(
            runs=runs,
            usage_duration_metrics=usage_duration_metrics,
            window_days=window_days,
            expense_type_scope=expense_type_scope,
        )
        payload = {
            "profile_type": result.profile_type,
            "profile_label": result.profile_label,
            "score": result.profile_score,
            "level": result.profile_level,
            "metrics": result.metrics,
            "top_contributors": result.top_contributors(),
        }
        tags = build_profile_tags([payload], scene=scene)
        radar = build_profile_radar([payload], tags, scene=scene)

        return EmployeeProfileLatestRead(
            employee_id=account_id,
            employee_name=account_name,
            scene=scene,
            window_days=window_days,
            expense_type_scope=expense_type_scope,
            calculated_at=datetime.now(UTC),
            review_priority_score=0,
            review_priority_level="normal",
            review_priority_label=LEVEL_LABELS["normal"],
            profiles=[
                EmployeeProfileRead(
                    profile_type=payload["profile_type"],
                    profile_label=PROFILE_LABELS.get(
                        payload["profile_type"],
                        payload["profile_type"],
                    ),
                    score=payload["score"],
                    level=payload["level"],
                    level_label=LEVEL_LABELS.get(payload["level"], payload["level"]),
                    metrics=payload["metrics"],
                    top_contributors=payload["top_contributors"],
                )
            ],
            profile_tags=tags,
            radar=radar,
        )

    def _calculate_account_ai_usage_profile(
        self,
        *,
        runs: list[AgentRun],
        usage_duration_metrics: dict[str, Any],
        window_days: int,
        expense_type_scope: str,
    ):
        tool_calls = [tool for run in runs for tool in run.tool_calls]
        failed_calls = [
            tool for tool in tool_calls if str(tool.status or "").lower() not in {"success", "ok"}
        ]
        estimated_tokens = self._estimate_tokens(runs)
        token_mode = "estimated_token_count" if estimated_tokens else "unavailable"

        return evaluate_weighted_profile(
            "ai_usage",
            [
                ProfileComponent(
                    "ai_call_count_score",
                    "AI 调用次数",
                    score_by_bands(len(runs), [(0, 0), (3, 25), (10, 65), (20, 100)]),
                    len(runs),
                    "次",
                    Decimal("0.25"),
                ),
                ProfileComponent(
                    "token_cost_score",
                    "Token 使用强度",
                    score_by_bands(
                        estimated_tokens, [(0, 0), (2000, 25), (8000, 65), (20000, 100)]
                    ),
                    estimated_tokens,
                    "tokens",
                    Decimal("0.25"),
                ),
                ProfileComponent(
                    "ai_generated_claim_ratio_score",
                    "AI 生成申请比例",
                    score_by_bands(len(runs), [(0, 0), (2, 20), (8, 60), (16, 90)]),
                    len(runs),
                    "次",
                    Decimal("0.20"),
                ),
                ProfileComponent(
                    "failed_ai_call_score",
                    "AI 调用失败",
                    score_by_bands(len(failed_calls), [(0, 0), (1, 35), (3, 80)]),
                    len(failed_calls),
                    "次",
                    Decimal("0.10"),
                ),
            ],
            metrics={
                "window_days": window_days,
                "expense_type_scope": expense_type_scope,
                "peer_sample_size": 0,
                "ai_run_count": len(runs),
                "tool_call_count": len(tool_calls),
                "failed_tool_call_count": len(failed_calls),
                "token_count_mode": token_mode,
                "estimated_token_count": estimated_tokens,
                "exact_token_count": None,
                **usage_duration_metrics,
            },
        )

    def _fetch_account_runs(self, identifiers: set[str], cutoff: datetime) -> list[AgentRun]:
        normalized = {item for item in identifiers if str(item or "").strip()}
        if not normalized:
            return []
        stmt = (
            select(AgentRun)
            .options(selectinload(AgentRun.tool_calls))
            .where(
                AgentRun.route_json["tenant_id"].as_string() == self.tenant_id,
                AgentRun.ontology_json["tenant_id"].as_string() == self.tenant_id,
                AgentRun.started_at >= cutoff,
                AgentRun.user_id.in_(normalized),
            )
        )
        return list(self.db.scalars(stmt).all())
