"""
aiel_sdk.integrations.postgres.types
====================================

Stable datatypes for the AIEL Postgres SDK surface.
"""

from __future__ import annotations

from dataclasses import dataclass, field
from typing import Any, Dict, List, Optional, Tuple, Literal
Json = Dict[str, Any]


@dataclass(frozen=True)
class PostgresQueryRequest:
    """Request payload for ``postgres.query``."""

    sql: str
    params: Optional[Json] = None
    max_rows: Optional[int] = None

    def validate(self) -> None:
        if not (self.sql or "").strip():
            raise ValueError("PostgresQueryRequest.sql must be non-empty")
        if self.max_rows is not None and self.max_rows <= 0:
            raise ValueError("PostgresQueryRequest.max_rows must be > 0 when provided")

    def to_params(self) -> Json:
        self.validate()
        out: Json = {"sql": self.sql}
        if self.params is not None:
            out["params"] = dict(self.params)
        if self.max_rows is not None:
            out["max_rows"] = self.max_rows
        return out


@dataclass(frozen=True)
class PostgresConflictSpec:
    target: List[str]
    action: Literal["do_nothing", "do_update"]
    update_fields: Optional[List[str]] = None

    def validate(self) -> None:
        if not self.target or not all(isinstance(x, str) and x.strip() for x in self.target):
            raise ValueError("PostgresConflictSpec.target must be a non-empty list of strings")

        if self.action == "do_nothing":
            if self.update_fields:
                raise ValueError("update_fields must be empty when action='do_nothing'")
        elif self.action == "do_update":
            if not self.update_fields:
                raise ValueError("update_fields is required when action='do_update'")


@dataclass(frozen=True)
class PostgresInsertRequest:
    """Request payload for ``postgres.insert``."""

    table: str
    values: Json
    conflict: Optional[PostgresConflictSpec] = None
    returning: Optional[List[str]] = None
    idempotency_key: Optional[str] = None

    def validate(self) -> None:
        if not (self.table or "").strip():
            raise ValueError("PostgresInsertRequest.table must be non-empty")
        if not isinstance(self.values, dict) or not self.values:
            raise ValueError("PostgresInsertRequest.values must be a non-empty dict")

    def to_params(self) -> Json:
        self.validate()
        out: Json = {"table": self.table, "values": dict(self.values)}
        if (self.conflict or "").strip():
            out["conflict"] = self.conflict
        if self.returning is not None:
            out["returning"] = list(self.returning)
        if (self.idempotency_key or "").strip():
            out["idempotency_key"] = self.idempotency_key
        return out


@dataclass(frozen=True)
class PostgresQueryResult:
    """Typed view for ``postgres.query`` response."""

    rows: List[Json] = field(default_factory=list)
    row_count: Optional[int] = None
    raw: Json = field(default_factory=dict)

    @staticmethod
    def from_json(payload: Json) -> "PostgresQueryResult":
        rows_raw = payload.get("rows")
        rows: List[Json] = []
        if isinstance(rows_raw, list):
            rows = [dict(x) for x in rows_raw if isinstance(x, dict)]
        return PostgresQueryResult(
            rows=rows,
            row_count=payload.get("row_count"),
            raw=dict(payload or {}),
        )


@dataclass(frozen=True)
class PostgresInsertResult:
    """Typed view for ``postgres.insert`` response."""

    inserted: Optional[int] = None
    returning_rows: List[Json] = field(default_factory=list)
    raw: Json = field(default_factory=dict)

    @staticmethod
    def from_json(payload: Json) -> "PostgresInsertResult":
        returning_raw = payload.get("returning_rows")
        returning_rows: List[Json] = []
        if isinstance(returning_raw, list):
            returning_rows = [dict(x) for x in returning_raw if isinstance(x, dict)]
        return PostgresInsertResult(
            inserted=payload.get("inserted"),
            returning_rows=returning_rows,
            raw=dict(payload or {}),
        )


@dataclass(frozen=True)
class PostgresCapability:
    id: str
    label: str
    description: str
    group: str
    group_label: str
    action: str


@dataclass(frozen=True)
class PostgresCapabilities:
    items: Tuple[PostgresCapability, ...]

    def ids(self) -> List[str]:
        return [c.id for c in self.items]

    def actions(self) -> List[str]:
        return [c.action for c in self.items]


DEFAULT_POSTGRES_CAPABILITIES = PostgresCapabilities(
    items=(
        PostgresCapability(
            id="postgres:query:read",
            label="Run Query",
            description="Run a read SQL query against the configured Postgres resource.",
            group="Query",
            group_label="Postgres integration",
            action="postgres.query",
        ),
        PostgresCapability(
            id="postgres:insert:create",
            label="Insert Rows",
            description="Insert rows into a Postgres table.",
            group="Write",
            group_label="Postgres integration",
            action="postgres.insert",
        ),
    )
)
