"""
GET /onboarding response schema — PRD-HWONB-001 §7.3, PRD-HWONB-002.

Pydantic v2 style, matching the rest of the codebase (see
src/apps/admin/schemas/admin_common.py for the house style this follows:
plain BaseModel, ConfigDict(from_attributes=True) where a schema is built
directly from an ORM row).
"""

from __future__ import annotations

from datetime import datetime
from typing import Any, Dict, List, Optional

from pydantic import BaseModel, ConfigDict, Field


class SectionState(BaseModel):
    """Per-section save bookkeeping, one entry per key in `section_state`."""

    pushed: bool = False
    tsys_errors: Optional[List[Dict[str, str]]] = None
    pushed_at: Optional[datetime] = None


class OnboardingApplicationResponse(BaseModel):
    """
    Full resumable state returned by `GET /onboarding`.

    `section_state` is a dict keyed by section name (application_setup,
    business, processing, addresses, accounts, owners, card_types, products,
    training_activation, fees, documents) — see SectionState for each value's
    shape. It is
    intentionally left as `Dict[str, Any]` rather than a strict
    `Dict[str, SectionState]` here so that a section developer adding a new
    key doesn't require a schema change in this shared file; validate the
    per-section shape at the point each section is written instead.

    Per-section snapshot fields (`business_data`, `processing_data`, ...)
    mirror the JSON snapshot columns on MerchantOnboardingApplication —
    each is the last-saved payload for that section, pre-encryption fields
    only (owners/accounts have their own tables and are NOT snapshotted
    here; see `owners_count`/`accounts_count` for a resume-summary instead).
    """

    model_config = ConfigDict(from_attributes=True)

    id: int
    merchant_id: int
    status: str
    current_step: str

    tsys_app_id: Optional[int] = None
    tsys_mid: Optional[str] = None
    tsys_association: Optional[str] = None
    tsys_lead_source: Optional[str] = None
    tsys_sales_rep: Optional[int] = None

    section_state: Dict[str, Any] = Field(default_factory=dict)

    business_data: Optional[Dict[str, Any]] = None
    processing_data: Optional[Dict[str, Any]] = None
    addresses_data: Optional[Dict[str, Any]] = None
    card_types_data: Optional[Dict[str, Any]] = None
    products_data: Optional[Dict[str, Any]] = None
    training_activation_data: Optional[Dict[str, Any]] = None
    fees_data: Optional[Dict[str, Any]] = None

    # Resume-summary counts for the two dedicated-table sections (owners,
    # accounts) — populated by services.start_or_resume(), not stored as a
    # column. Lets the wizard show "2 owners saved" without a second call.
    owners_count: int = 0
    accounts_count: int = 0
    documents_count: int = 0

    last_status_polled_at: Optional[datetime] = None
    last_tsys_status: Optional[str] = None

    submitted_email_sent_at: Optional[datetime] = None
    approved_email_sent_at: Optional[datetime] = None
    rejected_email_sent_at: Optional[datetime] = None

    created_at: datetime
    updated_at: Optional[datetime] = None


class LookupResponse(BaseModel):
    """Generic envelope for GET /onboarding/lookups/{type} — passes GP's own shape through."""

    type: str
    data: Any


class SectionSaveResponse(BaseModel):
    """
    Generic response for `PUT /onboarding/{section}` endpoints — shared
    across every section developer (services.save_section()'s intended
    shape, PRD-HWONB-001 §7 dispatcher docstring). On a GP `tsys_errors`
    rejection this is still a 200 (not an HTTP error) so the wizard can
    render field-level errors inline without a full error-page flow (AC-07);
    only unexpected/system failures raise APIException elsewhere.

    `data` carries any section-specific extra returned by GP worth surfacing
    to the wizard — e.g. Products' `terminalNumber` (PRD-HWONB-009 §6).
    """

    section: str
    pushed: bool
    tsys_errors: Optional[List[Dict[str, str]]] = None
    current_step: str
    data: Optional[Dict[str, Any]] = None
