"""Data models for the replay validation framework.

These are thin wrappers around the baseline JSON structure.  Deltas
are stored directly in ``BaselineData.table_deltas`` as plain dicts
and only deserialized into typed objects when needed for comparison.

The canonical representation is the JSON dict — Python objects exist
only to provide type hints and convenience accessors at comparison time.
"""

from __future__ import annotations

from enum import Enum
from typing import Any


RowDict = dict[str, Any]
"""A single database row represented as column-name -> value."""


class DeltaStrategy(str, Enum):
    """Supported delta-capture strategies."""

    FULL_SNAPSHOT = "full_snapshot"
    PK_DIFF = "pk_diff"
    SYNTHETIC_KEY = "synthetic_key"


class TableConfig:
    """Per-table replay settings resolved at runtime.

    Plain object — no dataclass overhead.  Built from CUR metadata +
    table inspector results, then passed to the strategy for capture.
    """

    __slots__ = (
        "schema_name", "table_name", "primary_key_columns",
        "estimated_row_count", "strategy", "ignore_columns",
    )

    def __init__(
        self,
        schema_name: str,
        table_name: str,
        primary_key_columns: list[str] | None = None,
        estimated_row_count: int = 0,
        strategy: DeltaStrategy = DeltaStrategy.FULL_SNAPSHOT,
        ignore_columns: list[str] | None = None,
    ) -> None:
        self.schema_name = schema_name
        self.table_name = table_name
        self.primary_key_columns = primary_key_columns or []
        self.estimated_row_count = estimated_row_count
        self.strategy = strategy
        self.ignore_columns = ignore_columns or []

    @property
    def fqn(self) -> str:
        return f"{self.schema_name}.{self.table_name}"


# ---------------------------------------------------------------------------
# Delta — thin wrapper around the baseline JSON dict
# ---------------------------------------------------------------------------

def make_delta(
    table: str,
    strategy_used: DeltaStrategy,
    inserts: list[RowDict] | None = None,
    deletes: list[RowDict] | None = None,
    updates: list[dict[str, Any]] | None = None,
) -> dict[str, Any]:
    """Create a delta dict in the canonical JSON-serializable format.

    This is a factory function, not a class — the delta IS the dict.
    Stored directly in ``BaselineData.table_deltas[fqn]``.
    """
    return {
        "table": table,
        "strategy_used": strategy_used.value,
        "inserts": inserts or [],
        "deletes": deletes or [],
        "updates": updates or [],
    }


def delta_total_changes(delta: dict[str, Any]) -> int:
    """Count total mutations in a delta dict."""
    return (
        len(delta.get("inserts", []))
        + len(delta.get("deletes", []))
        + len(delta.get("updates", []))
    )
