"""
Pydantic v2 models for the market-data pull endpoint.

This mirrors the request/response contract of the legacy `market-data.php`
file so existing consumers keep working, but the backing store is now
PostgreSQL (the IMDS tables populated by service_1) instead of MySQL.

Request actions:
  fetch_new_data      Incremental pull via ID-based (preferred) or
                      timestamp-based pagination.
  fetch_all           Full backfill via ID-based (preferred) or offset-based
                      pagination, with an optional `until_date` ceiling.
  fetch_day_end_data  Latest row per instrument for a given trade date
                      (imds_mkistat_data only).
"""

from __future__ import annotations

from typing import Any, Literal, Optional

from pydantic import BaseModel, Field, field_validator

# Tables the endpoint is allowed to read, mirroring the PHP allowlist.
ALLOWED_TABLES: tuple[str, ...] = (
    "imds_idx_data",
    "imds_man_data",
    "imds_mkistat_data",
    "imds_trd_data",
)

MarketDataAction = Literal["fetch_new_data", "fetch_all", "fetch_day_end_data"]


class MarketDataRequest(BaseModel):
    """
    Unified request body for POST /data/market-data.

    Field names are kept identical to the legacy PHP payload so existing
    clients require no changes.
    """

    action: MarketDataAction
    table: str

    # Pagination — ID-based is preferred (reliable, no row drift)
    last_id: Optional[int] = Field(
        default=None, ge=0, description="Cursor: return rows with primary key > last_id"
    )
    primary_key_column: Optional[str] = Field(
        default=None, description="Override the table's default primary key column"
    )

    # Pagination — timestamp / offset fallbacks
    last_timestamp: Optional[str] = Field(
        default=None, description="Cursor: return rows with timestamp column > value"
    )
    offset: int = Field(default=0, ge=0, description="Offset for offset-based paging")
    batch_size: int = Field(
        default=2000, ge=1, le=5000, description="Max rows per response (1–5000)"
    )

    # fetch_all date ceiling
    until_date: Optional[str] = Field(
        default=None, description="YYYY-MM-DD upper bound applied to timestamp_column"
    )
    timestamp_column: Optional[str] = Field(
        default=None, description="Timestamp column used together with until_date"
    )

    # fetch_day_end_data
    date: Optional[str] = Field(
        default=None, description="YYYY-MM-DD trade date for day-end snapshot"
    )

    @field_validator("table")
    @classmethod
    def _validate_table(cls, v: str) -> str:
        if v not in ALLOWED_TABLES:
            raise ValueError(f"Invalid table. Allowed: {', '.join(ALLOWED_TABLES)}")
        return v


class MarketDataResponse(BaseModel):
    """Response for fetch_new_data and fetch_all."""

    success: bool = True
    data: list[dict[str, Any]] = Field(default_factory=list)
    count: int = 0
    has_more: bool = False


class DayEndDataResponse(BaseModel):
    """Response for fetch_day_end_data."""

    success: bool = True
    data: list[dict[str, Any]] = Field(default_factory=list)
    count: int = 0
    date: str
