from __future__ import annotations

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

from app.api.deps import CurrentUserContext
from app.models.ai_learning import AIDecision, AIDecisionFeedback, WorkflowOutcome
from app.models.ai_memory import MemoryEvidenceLink
from app.models.expense_case import BusinessEvent, ExpenseCase
from app.models.financial_record import ExpenseClaim


class ExpenseApplicationMemoryEvidenceValidator:
    """校验个人记忆证据链及其租户、操作人和费用主体。"""

    def __init__(self, db: Session) -> None:
        self.db = db

    def validate(
        self,
        *,
        current_user: CurrentUserContext,
        decision: AIDecision,
        feedback: AIDecisionFeedback,
        outcome: WorkflowOutcome,
        claim: ExpenseClaim,
    ) -> None:
        self._validate_record_links(
            decision=decision,
            feedback=feedback,
            outcome=outcome,
            claim=claim,
        )
        allowed_actor_ids = self._allowed_actor_ids(current_user)
        evidence_actor_ids = {
            str(feedback.actor_id or "").strip().casefold(),
            str(outcome.actor_id or "").strip().casefold(),
        }
        if not allowed_actor_ids or not evidence_actor_ids.issubset(allowed_actor_ids):
            raise PermissionError("个人记忆证据的操作人与当前登录人不一致。")

        business_event = self.db.scalar(
            select(BusinessEvent).where(
                BusinessEvent.tenant_id == decision.tenant_id,
                BusinessEvent.expense_case_id == decision.expense_case_id,
                BusinessEvent.id == decision.business_event_id,
            )
        )
        if business_event is None:
            raise ValueError("个人记忆证据缺少可信的提交业务事件。")
        if (
            business_event.event_type != "application_submitted"
            or business_event.aggregate_type != "expense_claim"
            or business_event.aggregate_id != str(claim.id)
        ):
            raise ValueError("个人记忆证据关联的提交业务事件语义不一致。")
        if str(business_event.actor_id or "").strip().casefold() not in allowed_actor_ids:
            raise PermissionError("个人记忆证据的提交人与当前登录人不一致。")

        owner_employee_id = str(
            self.db.scalar(
                select(ExpenseCase.owner_employee_id).where(
                    ExpenseCase.tenant_id == decision.tenant_id,
                    ExpenseCase.id == decision.expense_case_id,
                )
            )
            or ""
        ).strip()
        current_employee_id = str(current_user.employee_id or "").strip()
        if (
            owner_employee_id
            and current_employee_id
            and owner_employee_id != current_employee_id
        ):
            raise PermissionError("个人记忆证据的费用 Case 不属于当前员工。")
        claim_employee_id = str(claim.employee_id or "").strip()
        if (
            claim_employee_id
            and current_employee_id
            and claim_employee_id != current_employee_id
        ):
            raise PermissionError("个人记忆证据的申请单不属于当前员工。")

    def list_currently_valid_links(
        self,
        *,
        tenant_id: str,
        memory_entry_id: str,
    ) -> list[MemoryEvidenceLink]:
        """只返回尚未失效、反转或降级的可信提交纠正证据。"""

        return list(
            self.db.scalars(
                select(MemoryEvidenceLink)
                .join(
                    AIDecisionFeedback,
                    and_(
                        AIDecisionFeedback.tenant_id
                        == MemoryEvidenceLink.tenant_id,
                        AIDecisionFeedback.id == MemoryEvidenceLink.feedback_id,
                    ),
                )
                .join(
                    WorkflowOutcome,
                    and_(
                        WorkflowOutcome.tenant_id == MemoryEvidenceLink.tenant_id,
                        WorkflowOutcome.id == MemoryEvidenceLink.outcome_id,
                    ),
                )
                .where(
                    MemoryEvidenceLink.tenant_id == tenant_id,
                    MemoryEvidenceLink.memory_entry_id == memory_entry_id,
                    AIDecisionFeedback.verification_status.in_(
                        ["server_verified", "human_verified"]
                    ),
                    AIDecisionFeedback.feedback_type == "edited",
                    AIDecisionFeedback.action_type == "submit",
                    WorkflowOutcome.outcome_type == "application_submitted",
                    WorkflowOutcome.outcome_status.in_(["recorded", "verified"]),
                )
                .order_by(MemoryEvidenceLink.created_at.asc())
            ).all()
        )

    @staticmethod
    def _validate_record_links(
        *,
        decision: AIDecision,
        feedback: AIDecisionFeedback,
        outcome: WorkflowOutcome,
        claim: ExpenseClaim,
    ) -> None:
        claim_ids = {
            str(claim.id or ""),
            str(decision.expense_claim_id or ""),
            str(feedback.expense_claim_id or ""),
            str(outcome.expense_claim_id or ""),
        }
        if len(claim_ids) != 1:
            raise ValueError("个人记忆证据关联的申请单不一致。")
        if feedback.decision_id != decision.id or outcome.decision_id != decision.id:
            raise ValueError("个人记忆证据关联的 AI 决策不一致。")
        if outcome.expense_case_id != decision.expense_case_id:
            raise ValueError("个人记忆证据关联的费用 Case 不一致。")
        if outcome.business_event_id != decision.business_event_id:
            raise ValueError("个人记忆证据关联的业务事件不一致。")

    @staticmethod
    def _allowed_actor_ids(current_user: CurrentUserContext) -> set[str]:
        return {
            value.casefold()
            for value in (
                str(current_user.username or "").strip(),
                str(current_user.employee_id or "").strip(),
            )
            if value
        }
