from __future__ import annotations

from typing import Any

from app.api.deps import CurrentUserContext
from app.models.financial_record import ExpenseClaim
from app.services.budget import BudgetService
from app.services.expense_claim_budget_risk_flags import dedupe_budget_risk_flags
from app.services.expense_claim_risk_stage import enrich_risk_flag_semantics


class ExpenseClaimBudgetFlowMixin:
    def _reserve_budget_for_submission(
        self,
        claim: ExpenseClaim,
        current_user: CurrentUserContext,
        *,
        is_application_claim: bool,
    ) -> list[dict[str, Any]]:
        source_type = "application" if is_application_claim else "claim"
        return BudgetService(self.db).reserve_for_claim(
            claim,
            source_type=source_type,
            operator=self._resolve_budget_operator(current_user),
        )

    def _release_budget_for_return(
        self,
        claim: ExpenseClaim,
        current_user: CurrentUserContext,
        *,
        reason: str,
    ) -> list[dict[str, Any]]:
        is_application_claim = self._is_expense_application_claim(claim)
        source_type = "application" if is_application_claim else "claim"
        return BudgetService(self.db).release_for_claim(
            claim,
            source_type=source_type,
            operator=self._resolve_budget_operator(current_user),
            reason=reason,
        )

    def _release_budget_for_delete(
        self,
        claim: ExpenseClaim,
        current_user: CurrentUserContext,
    ) -> None:
        is_application_claim = self._is_expense_application_claim(claim)
        source_type = "application" if is_application_claim else "claim"
        BudgetService(self.db).release_for_claim(
            claim,
            source_type=source_type,
            operator=self._resolve_budget_operator(current_user),
            reason="单据删除释放预算预占",
        )

    def _consume_budget_for_finance_approval(
        self,
        claim: ExpenseClaim,
        current_user: CurrentUserContext,
    ) -> dict[str, Any] | None:
        return BudgetService(self.db).consume_for_claim(
            claim,
            operator=self._resolve_budget_operator(current_user),
            reason="财务终审通过核销预算",
        )

    def _transfer_application_budget_to_reimbursement(
        self,
        *,
        application_claim: ExpenseClaim,
        draft_claim: ExpenseClaim,
        current_user: CurrentUserContext,
    ) -> dict[str, Any] | None:
        return BudgetService(self.db).transfer_application_reservation(
            application_claim=application_claim,
            draft_claim=draft_claim,
            operator=self._resolve_budget_operator(current_user),
        )

    @staticmethod
    def _append_budget_flags(
        risk_flags: list[Any] | None,
        budget_flags: list[dict[str, Any]] | dict[str, Any] | None,
        *,
        business_stage: str | None = None,
    ) -> list[Any]:
        if budget_flags is None:
            return list(risk_flags or [])
        if isinstance(budget_flags, dict):
            next_flags = [budget_flags]
        else:
            next_flags = list(budget_flags or [])
        if not next_flags:
            return list(risk_flags or [])
        enriched_flags = [
            enrich_risk_flag_semantics(
                flag,
                business_stage=business_stage,
                risk_domain="budget",
                visibility_scope="budget_manager",
                actionability="budget_governance",
            )
            if isinstance(flag, dict)
            else flag
            for flag in next_flags
        ]
        return dedupe_budget_risk_flags([*list(risk_flags or []), *enriched_flags])

    @staticmethod
    def _resolve_budget_operator(current_user: CurrentUserContext) -> str:
        return current_user.name or current_user.username or "system"
