from __future__ import annotations

from datetime import datetime
from typing import Any

from sqlalchemy import (
    Boolean,
    CheckConstraint,
    DateTime,
    Float,
    Index,
    Integer,
    String,
    Text,
    UniqueConstraint,
    func,
)
from sqlalchemy.orm import Mapped, mapped_column
from sqlalchemy.types import JSON

from app.db.base_class import Base


class AttachmentAssociationJob(Base):
    """可跨进程恢复的票据归集任务状态。"""

    __tablename__ = "attachment_association_jobs"
    __table_args__ = (
        UniqueConstraint(
            "tenant_id",
            "owner_username",
            "dedupe_key",
            "generation",
            name="uq_attachment_association_jobs_owner_dedupe",
        ),
        CheckConstraint(
            "status IN ('queued', 'running', 'succeeded', 'failed')",
            name="ck_attachment_association_jobs_status",
        ),
        CheckConstraint(
            "attempt_count >= 0",
            name="ck_attachment_association_jobs_attempt_count",
        ),
        CheckConstraint(
            "generation >= 1",
            name="ck_attachment_association_jobs_generation",
        ),
        CheckConstraint(
            "status != 'running' OR lease_expires_at IS NOT NULL",
            name="ck_attachment_association_jobs_running_lease",
        ),
        Index(
            "ix_attachment_association_jobs_owner_time",
            "tenant_id",
            "owner_username",
            "created_at",
        ),
        Index(
            "ix_attachment_association_jobs_status_lease",
            "status",
            "lease_expires_at",
        ),
    )

    id: Mapped[str] = mapped_column(String(80), primary_key=True)
    tenant_id: Mapped[str] = mapped_column(String(64), nullable=False)
    owner_username: Mapped[str] = mapped_column(String(255), nullable=False)
    owner_name: Mapped[str] = mapped_column(String(255), nullable=False, default="")
    owner_context_json: Mapped[dict[str, Any]] = mapped_column(JSON, nullable=False, default=dict)
    dedupe_key: Mapped[str] = mapped_column(String(64), nullable=False)
    generation: Mapped[int] = mapped_column(Integer, nullable=False, default=1)
    receipt_ids_json: Mapped[list[str]] = mapped_column(JSON, nullable=False, default=list)
    prompt: Mapped[str] = mapped_column(Text, nullable=False, default="")
    conversation_id: Mapped[str] = mapped_column(String(120), nullable=False, default="")
    status: Mapped[str] = mapped_column(String(20), nullable=False, default="queued")
    message: Mapped[str] = mapped_column(Text, nullable=False, default="")
    claim_id: Mapped[str] = mapped_column(String(36), nullable=False, default="")
    claim_no: Mapped[str] = mapped_column(String(80), nullable=False, default="")
    uploaded_count: Mapped[int] = mapped_column(Integer, nullable=False, default=0)
    skipped_count: Mapped[int] = mapped_column(Integer, nullable=False, default=0)
    resolution: Mapped[str] = mapped_column(String(40), nullable=False, default="pending")
    requires_confirmation: Mapped[bool] = mapped_column(Boolean, nullable=False, default=False)
    expense_case_id: Mapped[str] = mapped_column(String(36), nullable=False, default="")
    application_claim_id: Mapped[str] = mapped_column(String(36), nullable=False, default="")
    application_claim_no: Mapped[str] = mapped_column(String(80), nullable=False, default="")
    confidence: Mapped[str] = mapped_column(String(20), nullable=False, default="")
    confidence_score: Mapped[float] = mapped_column(Float, nullable=False, default=0.0)
    match_reasons_json: Mapped[list[str]] = mapped_column(JSON, nullable=False, default=list)
    exceptions_json: Mapped[list[str]] = mapped_column(JSON, nullable=False, default=list)
    missing_fields_json: Mapped[list[str]] = mapped_column(JSON, nullable=False, default=list)
    risk_items_json: Mapped[list[str]] = mapped_column(JSON, nullable=False, default=list)
    candidates_json: Mapped[list[dict[str, Any]]] = mapped_column(JSON, nullable=False, default=list)
    draft_payload_json: Mapped[dict[str, Any] | None] = mapped_column(JSON, nullable=True)
    error: Mapped[str] = mapped_column(Text, nullable=False, default="")
    attempt_count: Mapped[int] = mapped_column(Integer, nullable=False, default=0)
    lease_expires_at: Mapped[datetime | None] = mapped_column(
        DateTime(timezone=True),
        nullable=True,
    )
    created_at: Mapped[datetime] = mapped_column(
        DateTime(timezone=True),
        server_default=func.now(),
        nullable=False,
    )
    updated_at: Mapped[datetime] = mapped_column(
        DateTime(timezone=True),
        server_default=func.now(),
        onupdate=func.now(),
        nullable=False,
    )
