from __future__ import annotations

from datetime import UTC, date, datetime
from decimal import Decimal

from sqlalchemy import select

from app.core.agent_enums import (
    AgentName,
    AgentPermissionLevel,
    AgentRunSource,
    AgentRunStatus,
    AgentToolType,
)
from app.core.logging import get_logger
from app.models.agent_asset import AgentAsset
from app.models.agent_run import AgentRun, AgentToolCall, SemanticParseLog
from app.models.audit_log import AuditLog
from app.models.financial_record import (
    AccountsPayableRecord,
    AccountsReceivableRecord,
    ExpenseClaim,
    ExpenseClaimItem,
)
from app.services.agent_asset_access import platform_asset_statement
from app.services.agent_foundation_constants import (
    ATTACHMENT_RULE_ASSET_CODE,
    DEMO_EXPENSE_CLAIM_SIGNATURES,
    DEMO_PAYABLE_SIGNATURES,
    DEMO_RECEIVABLE_SIGNATURES,
    DIGITAL_EMPLOYEE_FINANCE_POLICY_TASK_CODE,
)
from app.services.tenant_registry import DEFAULT_TENANT_ID

logger = get_logger("app.services.agent_foundation")

class AgentFoundationFinancialSeedMixin:
    def _seed_financial_records(self) -> None:

        if self.db.scalar(
            select(ExpenseClaim.id)
            .where(ExpenseClaim.tenant_id == DEFAULT_TENANT_ID)
            .limit(1)
        ) is not None:

            return

        claim_1 = ExpenseClaim(

            tenant_id=DEFAULT_TENANT_ID,

            claim_no="EXP-202605-001",

            employee_name="张三",

            department_name="财务共享中心",

            project_code="PRJ-EXP-01",

            expense_type="travel",

            reason="华南客户拜访差旅报销",

            location="深圳",

            amount=Decimal("3280.00"),

            currency="CNY",

            invoice_count=3,

            occurred_at=datetime(2026, 5, 6, 9, 0, tzinfo=UTC),

            submitted_at=datetime(2026, 5, 7, 10, 20, tzinfo=UTC),

            status="submitted",

            approval_stage="finance_review",

            risk_flags_json=["amount_over_limit"],

        )

        claim_1.items = [

            ExpenseClaimItem(

                item_date=date(2026, 5, 5),

                item_type="hotel",

                item_reason="客户拜访住宿",

                item_location="深圳",

                item_amount=Decimal("1880.00"),

                invoice_id="INV-HOTEL-001",

            ),

            ExpenseClaimItem(

                item_date=date(2026, 5, 6),

                item_type="transport",

                item_reason="往返交通",

                item_location="深圳",

                item_amount=Decimal("1400.00"),

                invoice_id="INV-TRANS-009",

            ),

        ]

        claim_2 = ExpenseClaim(

            tenant_id=DEFAULT_TENANT_ID,

            claim_no="EXP-202605-002",

            employee_name="李四",

            department_name="华东销售部",

            project_code="PRJ-SALES-02",

            expense_type="meal",

            reason="客户路演餐费",

            location="上海",

            amount=Decimal("860.00"),

            currency="CNY",

            invoice_count=1,

            occurred_at=datetime(2026, 5, 8, 12, 0, tzinfo=UTC),

            submitted_at=datetime(2026, 5, 8, 18, 30, tzinfo=UTC),

            status="approved",

            approval_stage="completed",

            risk_flags_json=[],

        )

        claim_3 = ExpenseClaim(

            tenant_id=DEFAULT_TENANT_ID,

            claim_no="EXP-202605-003",

            employee_name="王五",

            department_name="市场品牌部",

            project_code="PRJ-MKT-08",

            expense_type="travel",

            reason="市场活动会务差旅",

            location="北京",

            amount=Decimal("3280.00"),

            currency="CNY",

            invoice_count=2,

            occurred_at=datetime(2026, 5, 6, 11, 30, tzinfo=UTC),

            submitted_at=datetime(2026, 5, 8, 9, 10, tzinfo=UTC),

            status="review",

            approval_stage="risk_check",

            risk_flags_json=["duplicate_expense"],

        )

        ar_records = [

            AccountsReceivableRecord(
                tenant_id=DEFAULT_TENANT_ID,

                receivable_no="AR-202605-001",

                customer_id="CUS-A",

                customer_name="客户A",

                contract_no="CTR-AR-1001",

                invoice_no="INV-AR-9001",

                amount_receivable=Decimal("120000.00"),

                amount_received=Decimal("70000.00"),

                amount_outstanding=Decimal("50000.00"),

                currency="CNY",

                posting_date=date(2026, 4, 1),

                due_date=date(2026, 4, 30),

                aging_days=11,

                status="partial",

                risk_flags_json=[],

            ),

            AccountsReceivableRecord(
                tenant_id=DEFAULT_TENANT_ID,

                receivable_no="AR-202605-002",

                customer_id="CUS-B",

                customer_name="客户B",

                contract_no="CTR-AR-1002",

                invoice_no="INV-AR-9002",

                amount_receivable=Decimal("88000.00"),

                amount_received=Decimal("10000.00"),

                amount_outstanding=Decimal("78000.00"),

                currency="CNY",

                posting_date=date(2026, 3, 15),

                due_date=date(2026, 4, 15),

                aging_days=26,

                status="overdue",

                risk_flags_json=["ar_overdue"],

            ),

        ]

        ap_records = [

            AccountsPayableRecord(
                tenant_id=DEFAULT_TENANT_ID,

                payable_no="AP-202605-001",

                vendor_id="VEN-A",

                vendor_name="供应商A",

                invoice_no="INV-AP-5001",

                amount_payable=Decimal("43000.00"),

                amount_paid=Decimal("10000.00"),

                amount_outstanding=Decimal("33000.00"),

                currency="CNY",

                posting_date=date(2026, 4, 20),

                due_date=date(2026, 5, 12),

                aging_days=0,

                status="scheduled",

                risk_flags_json=[],

            ),

            AccountsPayableRecord(
                tenant_id=DEFAULT_TENANT_ID,

                payable_no="AP-202605-002",

                vendor_id="VEN-B",

                vendor_name="供应商B",

                invoice_no="INV-AP-5002",

                amount_payable=Decimal("96000.00"),

                amount_paid=Decimal("0.00"),

                amount_outstanding=Decimal("96000.00"),

                currency="CNY",

                posting_date=date(2026, 4, 10),

                due_date=date(2026, 5, 5),

                aging_days=6,

                status="overdue",

                risk_flags_json=["ap_overdue"],

            ),

        ]

        self.db.add_all([claim_1, claim_2, claim_3, *ar_records, *ap_records])

    def _purge_demo_financial_records(self) -> None:

        demo_claims = list(
            self.db.scalars(
                select(ExpenseClaim).where(
                    ExpenseClaim.tenant_id == DEFAULT_TENANT_ID
                )
            ).all()
        )

        for claim in demo_claims:

            signature = (

                str(claim.claim_no or "").strip(),

                str(claim.employee_name or "").strip(),

                str(claim.reason or "").strip(),

                f"{Decimal(claim.amount or 0):.2f}",

                str(claim.status or "").strip(),

            )

            if signature in DEMO_EXPENSE_CLAIM_SIGNATURES:

                self.db.delete(claim)

        demo_receivables = list(
            self.db.scalars(
                select(AccountsReceivableRecord).where(
                    AccountsReceivableRecord.tenant_id == DEFAULT_TENANT_ID
                )
            ).all()
        )

        for record in demo_receivables:

            signature = (

                str(record.receivable_no or "").strip(),

                str(record.customer_name or "").strip(),

                f"{Decimal(record.amount_outstanding or 0):.2f}",

                str(record.status or "").strip(),

            )

            if signature in DEMO_RECEIVABLE_SIGNATURES:

                self.db.delete(record)

        demo_payables = list(
            self.db.scalars(
                select(AccountsPayableRecord).where(
                    AccountsPayableRecord.tenant_id == DEFAULT_TENANT_ID
                )
            ).all()
        )

        for record in demo_payables:

            signature = (

                str(record.payable_no or "").strip(),

                str(record.vendor_name or "").strip(),

                f"{Decimal(record.amount_outstanding or 0):.2f}",

                str(record.status or "").strip(),

            )

            if signature in DEMO_PAYABLE_SIGNATURES:

                self.db.delete(record)

    def _seed_runs_and_logs(self) -> None:

        if self.db.scalar(select(AgentRun.id).limit(1)) is not None:

            return

        task_asset = self.db.scalar(

            platform_asset_statement().where(
                AgentAsset.code == DIGITAL_EMPLOYEE_FINANCE_POLICY_TASK_CODE
            )

        )

        user_run = AgentRun(

            run_id="run_user_20260511_001",

            agent=AgentName.USER_AGENT.value,

            source=AgentRunSource.USER_MESSAGE.value,

            user_id="emp_001",

            task_id=None,

            ontology_json={"scenario": "expense", "intent": "query"},

            route_json={"selected_agent": AgentName.USER_AGENT.value, "route_reason": "user query"},

            permission_level=AgentPermissionLevel.READ.value,

            status=AgentRunStatus.SUCCEEDED.value,

            result_summary="已返回本周报销金额和风险摘要。",

            started_at=datetime(2026, 5, 11, 8, 35, tzinfo=UTC),

            finished_at=datetime(2026, 5, 11, 8, 35, 2, tzinfo=UTC),

        )

        hermes_run = AgentRun(

            run_id="run_hermes_20260511_001",

            agent=AgentName.HERMES.value,

            source=AgentRunSource.SCHEDULE.value,

            user_id=None,

            task_id=task_asset.id if task_asset else None,

            ontology_json={"scenario": "expense", "intent": "risk_check"},

            route_json={

                "selected_agent": AgentName.HERMES.value,

                "route_reason": "scheduled risk scan",

            },

            permission_level=AgentPermissionLevel.READ.value,

            status=AgentRunStatus.SUCCEEDED.value,

            result_summary="Hermes 已生成今日风险巡检摘要。",

            started_at=datetime(2026, 5, 11, 9, 0, tzinfo=UTC),

            finished_at=datetime(2026, 5, 11, 9, 0, 4, tzinfo=UTC),

        )

        blocked_run = AgentRun(

            run_id="run_user_20260511_002",

            agent=AgentName.ORCHESTRATOR.value,

            source=AgentRunSource.USER_MESSAGE.value,

            user_id="emp_002",

            task_id=None,

            ontology_json={"scenario": "accounts_payable", "intent": "operate"},

            route_json={

                "selected_agent": AgentName.USER_AGENT.value,

                "route_reason": "payment request",

            },

            permission_level=AgentPermissionLevel.APPROVAL_REQUIRED.value,

            status=AgentRunStatus.BLOCKED.value,

            result_summary="动作需要人工确认。",

            error_message="直接付款属于高风险动作，已阻断自动执行。",

            started_at=datetime(2026, 5, 11, 10, 5, tzinfo=UTC),

            finished_at=datetime(2026, 5, 11, 10, 5, 1, tzinfo=UTC),

        )

        self.db.add_all([user_run, hermes_run, blocked_run])

        self.db.flush()

        self.db.add_all(

            [

                AgentToolCall(

                    run_id=user_run.run_id,

                    tool_type=AgentToolType.DATABASE.value,

                    tool_name="expense_claims.lookup",

                    request_json={"time_range": "this_week", "employee": "all"},

                    response_json={"claim_count": 3, "total_amount": "7420.00"},

                    status="succeeded",

                    duration_ms=48,

                ),

                AgentToolCall(

                    run_id=hermes_run.run_id,

                    tool_type=AgentToolType.MCP.value,

                    tool_name="invoice.verify_mock",

                    request_json={"claim_no": "EXP-202605-003"},

                    response_json={

                        "warning": "external service degraded",

                        "fallback": "used mock response",

                    },

                    status="failed",

                    duration_ms=132,

                    error_message="mock upstream timeout",

                ),

                AgentToolCall(

                    run_id=blocked_run.run_id,

                    tool_type=AgentToolType.RULE_ENGINE.value,

                    tool_name="permission.guard",

                    request_json={"action": "direct_payment"},

                    response_json={"requires_confirmation": True},

                    status="succeeded",

                    duration_ms=5,

                ),

                SemanticParseLog(

                    run_id=user_run.run_id,

                    user_id="emp_001",

                    raw_query="查一下本周报销超标风险",

                    scenario="expense",

                    intent="risk_check",

                    entities_json=[],

                    time_range_json={"start_date": "2026-05-11", "end_date": "2026-05-17"},

                    metrics_json=["amount"],

                    constraints_json=[],

                    risk_flags_json=["amount_over_limit"],

                    permission_json={"level": AgentPermissionLevel.READ.value},

                    confidence=0.93,

                ),

                SemanticParseLog(

                    run_id=blocked_run.run_id,

                    user_id="emp_002",

                    raw_query="帮我直接付款给供应商B",

                    scenario="accounts_payable",

                    intent="operate",

                    entities_json=[{"type": "vendor", "value": "供应商B"}],

                    time_range_json={},

                    metrics_json=["amount"],

                    constraints_json=[],

                    risk_flags_json=["ap_overdue"],

                    permission_json={"level": AgentPermissionLevel.APPROVAL_REQUIRED.value},

                    confidence=0.96,

                ),

            ]

        )

        if self.db.scalar(select(AuditLog.id).limit(1)) is None:

            self.db.add_all(

                [

                    AuditLog(

                        actor="系统初始化",

                        action="save_rule_markdown",

                        resource_type="rule",

                        resource_id=ATTACHMENT_RULE_ASSET_CODE,

                        before_json=None,

                        after_json={"version": "v1.0.0"},

                        request_id="seed-audit-001",

                    ),

                    AuditLog(

                        actor="高嘉禾",

                        action="review_rule",

                        resource_type="rule",

                        resource_id=ATTACHMENT_RULE_ASSET_CODE,

                        before_json={"review_status": "pending"},

                        after_json={"review_status": "pending"},

                        request_id="seed-audit-002",

                    ),

                    AuditLog(

                        actor="系统初始化",

                        action="activate_rule",

                        resource_type="rule",

                        resource_id="rule.expense.scene_submission_standard",

                        before_json={"status": "draft"},

                        after_json={"status": "active"},

                        request_id="seed-audit-003",

                    ),

                    AuditLog(

                        actor="Hermes",

                        action="update_task_status",

                        resource_type="task",

                        resource_id=DIGITAL_EMPLOYEE_FINANCE_POLICY_TASK_CODE,

                        before_json={"status": "idle"},

                        after_json={"status": "succeeded"},

                        request_id="seed-audit-004",

                    ),

                ]

            )
