"""
PRD-HWONB-001 §6.1 — merchant_onboarding_applications

One row per merchant's Global Payments Base Boarding underwriting application.
The CRUD layer (not this module) enforces "one active (deleted_at IS NULL) row
per merchant".
"""
from typing import Optional, TYPE_CHECKING
from sqlalchemy import String, Integer, DateTime, JSON, ForeignKey
from sqlalchemy.orm import Mapped, mapped_column, relationship
from sqlalchemy.sql import func
from src.apps.base.models.base import Base
from datetime import datetime

if TYPE_CHECKING:
    from src.apps.merchant_onboarding.models.owner import MerchantOnboardingOwner
    from src.apps.merchant_onboarding.models.account import MerchantOnboardingAccount
    from src.apps.merchant_onboarding.models.document import MerchantOnboardingDocument

# status: draft|in_progress|ready_to_transmit|transmitted|in_process|pending|approved|provisioned|rejected|error
# current_step: application_setup|business|processing|addresses|accounts|owners|card_types|products|training_activation|fees|documents|review
# Both are plain String columns, not DB enums — the state machine (helpers/status_machine.py,
# Developer's job) validates transitions in code, per PRD-HWONB-001 §6.1/§7.2.


class MerchantOnboardingApplication(Base):
    __tablename__ = "merchant_onboarding_applications"

    id: Mapped[int] = mapped_column(Integer, primary_key=True, index=True, autoincrement=True)
    merchant_id: Mapped[int] = mapped_column(Integer, ForeignKey("merchants.id"), nullable=False, index=True)

    # Global Payments identifiers — set once the invisible bootstrap (PRD-HWONB-002)
    # creates the application, and once transmit/approval issues a MID.
    tsys_app_id: Mapped[Optional[int]] = mapped_column(Integer, nullable=True)
    tsys_mid: Mapped[Optional[str]] = mapped_column(String(25), nullable=True)

    # PRD-HWONB-015 — the merchant's chosen GP pricing tier, lead source, and
    # sales rep (options from the partner's `GET /masterRecord/{type}` lookups),
    # collected in the Application Setup step and sent on the real
    # `POST /applications` Create Application call itself (not patched in
    # afterward — see PRD-HWONB-015, which supersedes PRD-HWONB-014's
    # bootstrap-then-PATCH flow for `association`).
    tsys_association: Mapped[Optional[str]] = mapped_column(String(6), nullable=True)
    tsys_lead_source: Mapped[Optional[str]] = mapped_column(String(10), nullable=True)
    tsys_sales_rep: Mapped[Optional[int]] = mapped_column(Integer, nullable=True)

    status: Mapped[str] = mapped_column(String(30), default="draft", nullable=False)
    current_step: Mapped[str] = mapped_column(String(30), default="application_setup", nullable=False)

    # {application_setup:{pushed,tsys_errors,pushed_at}, business:{...}, processing:{...},
    #  addresses:{...}, accounts:{...}, owners:{...}, card_types:{...}, products:{...},
    #  training_activation:{...}, fees:{...}, documents:{...}}
    section_state: Mapped[Optional[dict]] = mapped_column(JSON, nullable=True)

    # Snapshot of each section's last-saved payload (pre-encryption fields only) — used for
    # resume/audit; Owners/Accounts have their own dedicated tables and are not snapshotted here.
    business_data: Mapped[Optional[dict]] = mapped_column(JSON, nullable=True)
    processing_data: Mapped[Optional[dict]] = mapped_column(JSON, nullable=True)
    addresses_data: Mapped[Optional[dict]] = mapped_column(JSON, nullable=True)
    card_types_data: Mapped[Optional[dict]] = mapped_column(JSON, nullable=True)
    products_data: Mapped[Optional[dict]] = mapped_column(JSON, nullable=True)
    training_activation_data: Mapped[Optional[dict]] = mapped_column(JSON, nullable=True)
    fees_data: Mapped[Optional[dict]] = mapped_column(JSON, nullable=True)

    last_status_polled_at: Mapped[Optional[datetime]] = mapped_column(DateTime(timezone=True), nullable=True)
    last_tsys_status: Mapped[Optional[str]] = mapped_column(String(50), nullable=True)
    tsys_decision_payload: Mapped[Optional[dict]] = mapped_column(JSON, nullable=True)

    submitted_email_sent_at: Mapped[Optional[datetime]] = mapped_column(DateTime(timezone=True), nullable=True)
    approved_email_sent_at: Mapped[Optional[datetime]] = mapped_column(DateTime(timezone=True), nullable=True)
    rejected_email_sent_at: Mapped[Optional[datetime]] = 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[Optional[datetime]] = mapped_column(DateTime(timezone=True), nullable=True, onupdate=func.now())
    deleted_at: Mapped[Optional[datetime]] = mapped_column(DateTime(timezone=True), nullable=True)

    owners: Mapped[list["MerchantOnboardingOwner"]] = relationship(
        "MerchantOnboardingOwner", back_populates="application", cascade="all, delete-orphan"
    )
    accounts: Mapped[list["MerchantOnboardingAccount"]] = relationship(
        "MerchantOnboardingAccount", back_populates="application", cascade="all, delete-orphan"
    )
    documents: Mapped[list["MerchantOnboardingDocument"]] = relationship(
        "MerchantOnboardingDocument", back_populates="application", cascade="all, delete-orphan"
    )
