from __future__ import annotations

import uuid
from datetime import datetime
from typing import Any

from sqlalchemy import CheckConstraint, DateTime, Index, String, UniqueConstraint, func
from sqlalchemy.orm import Mapped, mapped_column
from sqlalchemy.types import JSON

from app.db.base_class import Base


class ApprovalActionLedger(Base):
    """审批类写动作的持久化幂等账本。"""

    __tablename__ = "approval_action_ledgers"
    __table_args__ = (
        CheckConstraint(
            "action IN ('approve', 'return', 'pay')",
            name="ck_approval_action_ledger_action",
        ),
        CheckConstraint(
            "(completed_at IS NULL AND result_status IS NULL "
            "AND result_approval_stage IS NULL) OR "
            "(completed_at IS NOT NULL AND result_status IS NOT NULL "
            "AND result_approval_stage IS NOT NULL)",
            name="ck_approval_action_ledger_completion",
        ),
        UniqueConstraint(
            "tenant_id",
            "actor_id",
            "request_id",
            name="uq_approval_action_ledger_request",
        ),
        Index(
            "ix_approval_action_ledger_claim_action",
            "tenant_id",
            "claim_id",
            "action",
        ),
    )

    id: Mapped[str] = mapped_column(
        String(36),
        primary_key=True,
        default=lambda: str(uuid.uuid4()),
    )
    tenant_id: Mapped[str] = mapped_column(String(64), nullable=False)
    actor_id: Mapped[str] = mapped_column(String(120), nullable=False)
    request_id: Mapped[str] = mapped_column(String(120), nullable=False)
    claim_id: Mapped[str] = mapped_column(String(36), nullable=False)
    action: Mapped[str] = mapped_column(String(20), nullable=False)
    payload_fingerprint: Mapped[str] = mapped_column(String(80), nullable=False)
    expected_status: Mapped[str] = mapped_column(String(30), nullable=False)
    expected_approval_stage: Mapped[str] = mapped_column(String(50), nullable=False)
    result_status: Mapped[str | None] = mapped_column(String(30), nullable=True)
    result_approval_stage: Mapped[str | None] = mapped_column(String(50), nullable=True)
    response_json: Mapped[dict[str, Any] | None] = mapped_column(JSON, nullable=True)
    completed_at: Mapped[datetime | None] = mapped_column(DateTime(timezone=True), nullable=True)
    created_at: Mapped[datetime] = mapped_column(
        DateTime(timezone=True),
        server_default=func.now(),
    )
