"""Public (signed-out) read access to a datasource or form — see
app/crud/public_data.py."""

import uuid
from datetime import datetime
from typing import Literal

from pydantic import BaseModel, ConfigDict, Field

from app.schemas.reporting import DatasetAggregateFn, DatasetDateBucket, DatasetFilterItem, DatasetSortDir

PublicDataSourceType = Literal["master", "form"]


class PublicDataConfig(BaseModel):
    """What a signed-out visitor may read of one source."""

    enabled: bool = False
    # The fields visitors may see (and filter, sort and search on).
    fields: list[str] = []
    # Every public read is narrowed by these, e.g. status = Published.
    filters: list[DatasetFilterItem] = []
    # Visitors may search the shown text fields.
    allow_search: bool = True


class PublicDataConfigRead(PublicDataConfig):
    model_config = ConfigDict(from_attributes=True)
    source_type: PublicDataSourceType
    source_id: uuid.UUID
    updated_at: datetime | None = None


class PublicField(BaseModel):
    name: str
    label: str
    # As a visitor sees it: a linked record or a person reads as text.
    type: str
    options: list[str] | None = None


class PublicSourceSchema(BaseModel):
    source_type: PublicDataSourceType
    source_id: uuid.UUID
    name: str
    fields: list[PublicField]
    allow_search: bool


class PublicDataQuery(BaseModel):
    """A data block's read, as the dataset query (app/schemas/reporting.py::
    DatasetQueryRequest) minus what could reach past the public fields:
    no joins, calculated columns or custom expressions."""

    source_type: PublicDataSourceType
    source_id: uuid.UUID
    columns: list[str] = []
    filters: list[DatasetFilterItem] = []
    sort_field: str | None = None
    sort_dir: DatasetSortDir = "asc"
    group_by: str | None = None
    aggregate_field: str | None = None
    aggregate_fn: DatasetAggregateFn | None = None
    q: str | None = Field(default=None, max_length=200)
    skip: int = Field(default=0, ge=0, le=5000)
    limit: int = Field(default=50, ge=1, le=500)


class PublicSeriesDef(BaseModel):
    field: str | None = None
    aggregate: DatasetAggregateFn | None = None
    label: str | None = None


class PublicSeriesQuery(BaseModel):
    source_type: PublicDataSourceType
    source_id: uuid.UUID
    filters: list[DatasetFilterItem] = []
    x_field: str
    x_bucket: DatasetDateBucket = "none"
    series: list[PublicSeriesDef] = Field(min_length=1, max_length=10)
    limit: int = Field(default=200, ge=1, le=500)


class PublicDataResult(BaseModel):
    columns: list[str]
    rows: list[dict]
    total: int


class PublicSeriesResult(BaseModel):
    rows: list[dict]
    series: list[str]
