"""ORM model for hw_platform_bank_accounts.

Stores HubWallet-owned ACH destination accounts used for daily platform-fee
settlement sweeps.  Routing and account numbers are stored encrypted
(AES-256-GCM, base64-encoded ciphertext) — the plaintext values must never
be written to this table.

is_active uniqueness is NOT enforced by a database constraint.  The service
layer performs an atomic swap (deactivate-all then activate-one inside a
single transaction) to replace the active account.
"""
from __future__ import annotations

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

from sqlalchemy import Boolean, CheckConstraint, DateTime, ForeignKey, Integer, String, Text
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.users.models.user import User
    from src.apps.admin.models.fee_settlement_run import FeeSettlementRun


class AccountType(str, enum.Enum):
    CHECKING = "checking"
    SAVINGS = "savings"


class HWPlatformBankAccount(Base):
    """HubWallet-owned ACH bank account used to receive platform-fee settlements."""

    __tablename__ = "hw_platform_bank_accounts"
    __table_args__ = (
        CheckConstraint(
            "account_type IN ('checking', 'savings')",
            name="ck_hw_platform_bank_accounts_account_type",
        ),
    )

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

    # Display name shown in the admin UI (e.g. "Primary ACH Account")
    nickname: Mapped[str] = mapped_column(String(100), nullable=False)
    account_holder_name: Mapped[str] = mapped_column(String(200), nullable=False)
    bank_name: Mapped[Optional[str]] = mapped_column(String(200), nullable=True)

    # Encrypted fields — AES-256-GCM, base64-encoded.  Application layer handles
    # encrypt-on-write and decrypt-on-read; the ORM treats them as opaque strings.
    routing_number_enc: Mapped[str] = mapped_column(Text, nullable=False)
    account_number_enc: Mapped[str] = mapped_column(Text, nullable=False)

    # Last 4 digits stored in plaintext for display/audit purposes only
    account_number_last4: Mapped[str] = mapped_column(String(4), nullable=False)

    account_type: Mapped[str] = mapped_column(
        String(10), nullable=False, default=AccountType.CHECKING
    )

    # Only one account should be active at a time; enforced by service layer
    is_active: Mapped[bool] = mapped_column(
        Boolean, nullable=False, default=False, index=True
    )

    # Superuser who created this record; SET NULL on user deletion
    created_by_user_id: Mapped[Optional[int]] = mapped_column(
        Integer,
        ForeignKey("users.id", ondelete="SET NULL", name="fk_hw_platform_bank_accounts_created_by"),
        nullable=True,
        index=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()
    )
    deleted_at: Mapped[Optional[datetime]] = mapped_column(
        DateTime(timezone=True), nullable=True
    )

    # Relationships
    created_by: Mapped[Optional["User"]] = relationship(
        "User",
        foreign_keys=[created_by_user_id],
        uselist=False,
    )

    settlement_runs: Mapped[list["FeeSettlementRun"]] = relationship(
        "FeeSettlementRun",
        back_populates="settlement_account",
    )
