"""ORM model for fee_settlement_runs.

Immutable financial audit record for each daily platform-fee settlement
attempt.  One row per calendar day (settlement_date UNIQUE).

Design decisions:
- No deleted_at column — this table is append-only; rows must not be removed.
- total_fee_cents is BigInteger — the platform could accumulate > $21 K/day
  which overflows a 32-bit signed integer stored in cents.
- retry_count is SmallInteger — retries are bounded (typically <= 3) and do not
  need 32-bit range.
- triggered_by distinguishes scheduled runs from admin-triggered manual retries.
"""
from __future__ import annotations

import enum
from datetime import date, datetime
from typing import Optional, TYPE_CHECKING

from sqlalchemy import (
    BigInteger,
    CheckConstraint,
    Date,
    DateTime,
    ForeignKey,
    Integer,
    SmallInteger,
    String,
    Text,
    UniqueConstraint,
)
from sqlalchemy.orm import Mapped, mapped_column, relationship
from sqlalchemy.sql import func

from src.apps.base.models.base import Base

if TYPE_CHECKING:
    from src.apps.admin.models.hw_platform_bank_account import HWPlatformBankAccount
    from src.apps.transactions.models.transactions import Transactions


class SettlementRunStatus(str, enum.Enum):
    PENDING = "pending"
    PROCESSING = "processing"
    SETTLED = "settled"
    FAILED = "failed"
    SKIPPED = "skipped"


class SettlementTrigger(str, enum.Enum):
    SCHEDULER = "scheduler"
    MANUAL = "manual"


class FeeSettlementRun(Base):
    """Daily platform-fee settlement run record."""

    __tablename__ = "fee_settlement_runs"
    __table_args__ = (
        UniqueConstraint("settlement_date", name="uq_fee_settlement_runs_settlement_date"),
        CheckConstraint(
            "status IN ('pending', 'processing', 'settled', 'failed', 'skipped')",
            name="ck_fee_settlement_runs_status",
        ),
        CheckConstraint(
            "triggered_by IN ('scheduler', 'manual')",
            name="ck_fee_settlement_runs_triggered_by",
        ),
        CheckConstraint(
            "total_fee_cents >= 0",
            name="ck_fee_settlement_runs_total_fee_cents_non_negative",
        ),
        CheckConstraint(
            "transaction_count >= 0",
            name="ck_fee_settlement_runs_transaction_count_non_negative",
        ),
        CheckConstraint(
            "retry_count >= 0",
            name="ck_fee_settlement_runs_retry_count_non_negative",
        ),
    )

    id: Mapped[int] = mapped_column(Integer, primary_key=True, autoincrement=True)

    # Calendar date for which fees were settled — UNIQUE, one run per day
    settlement_date: Mapped[date] = mapped_column(Date, nullable=False, index=True)

    # Bank account that received the sweep for this run
    settlement_account_id: Mapped[int] = mapped_column(
        Integer,
        ForeignKey(
            "hw_platform_bank_accounts.id",
            ondelete="RESTRICT",
            name="fk_fee_settlement_runs_settlement_account",
        ),
        nullable=False,
        index=True,
    )

    # Aggregate counters — populated when the run claims transactions
    transaction_count: Mapped[int] = mapped_column(Integer, nullable=False, default=0)
    total_fee_cents: Mapped[int] = mapped_column(BigInteger, nullable=False, default=0)

    # Lifecycle status
    status: Mapped[str] = mapped_column(
        String(20), nullable=False, default=SettlementRunStatus.PENDING, index=True
    )

    # External processor reference returned after the ACH debit is submitted
    tsys_transaction_id: Mapped[Optional[str]] = mapped_column(String(255), nullable=True)

    # How this run was started
    triggered_by: Mapped[str] = mapped_column(
        String(20), nullable=False, default=SettlementTrigger.SCHEDULER
    )

    initiated_at: Mapped[datetime] = mapped_column(
        DateTime(timezone=True), server_default=func.now(), nullable=False
    )
    # Set when status transitions to 'settled'
    settled_at: Mapped[Optional[datetime]] = mapped_column(
        DateTime(timezone=True), nullable=True
    )

    # Retry tracking
    retry_count: Mapped[int] = mapped_column(SmallInteger, nullable=False, default=0)
    last_error: Mapped[Optional[str]] = mapped_column(Text, nullable=True)

    created_at: Mapped[datetime] = mapped_column(
        DateTime(timezone=True), server_default=func.now(), nullable=False
    )
    updated_at: Mapped[Optional[datetime]] = mapped_column(
        DateTime(timezone=True), nullable=True, onupdate=func.now()
    )

    # NOTE: No deleted_at — this table is an immutable financial audit log.
    #       Rows must never be deleted or soft-deleted.

    # Relationships
    settlement_account: Mapped["HWPlatformBankAccount"] = relationship(
        "HWPlatformBankAccount",
        back_populates="settlement_runs",
        uselist=False,
    )

    transactions: Mapped[list["Transactions"]] = relationship(
        "Transactions",
        back_populates="fee_settlement_run",
        foreign_keys="Transactions.fee_settlement_run_id",
    )
