"""Presentation-only rendering of existing App Block contracts (FL-D2).

These helpers reshape records already returned by admitted list/detail ports.
They do not introduce persistence, Reporting, Search, or workflow engines.
"""

from __future__ import annotations

from collections import defaultdict
from collections.abc import Mapping
from typing import Any

COMPACT_DASHBOARD_FORBIDDEN_KEYS = frozenset(
    {
        "timeseries",
        "time_series",
        "historical",
        "analytics",
        "report",
        "metric_definitions",
        "chart_query",
        "aggregation_api",
    }
)
KANBAN_GROUP_FIELDS = frozenset({"status", "stage"})


def _field(record: Mapping[str, Any], key: str) -> Any:
    return record.get(key)


def status_grouping(
    records: list[Mapping[str, Any]],
    *,
    group_by_field: str = "status",
) -> dict[str, list[Mapping[str, Any]]]:
    grouped: dict[str, list[Mapping[str, Any]]] = defaultdict(list)
    for record in records:
        grouped[str(_field(record, group_by_field) or "unspecified")].append(record)
    return dict(grouped)


def split_list_detail(
    records: list[Mapping[str, Any]],
    *,
    selected_id: str | None,
    detail: Mapping[str, Any] | None,
) -> dict[str, Any]:
    return {
        "list": list(records),
        "selected_id": selected_id,
        "detail": dict(detail) if detail is not None else None,
    }


def compact_dashboard(
    records: list[Mapping[str, Any]],
    *,
    group_by_field: str | None = "status",
    recent_limit: int = 5,
    primary_actions: list[str] | None = None,
) -> dict[str, Any]:
    groups = status_grouping(records, group_by_field=group_by_field) if group_by_field else {}
    payload = {
        "record_count": len(records),
        "group_counts": {key: len(items) for key, items in groups.items()},
        "recent": list(records[:recent_limit]),
        "primary_actions": list(primary_actions or []),
    }
    forbidden = COMPACT_DASHBOARD_FORBIDDEN_KEYS & payload.keys()
    if forbidden:
        raise ValueError(f"compact_dashboard collided with Reporting keys {sorted(forbidden)}")
    return payload


def kanban_grouping(
    records: list[Mapping[str, Any]],
    *,
    group_by_field: str = "status",
    move: Mapping[str, Any] | None = None,
    existing_status_patch: Any | None = None,
) -> dict[str, Any]:
    if group_by_field not in KANBAN_GROUP_FIELDS:
        raise ValueError("kanban_grouping may only group by an authored status/stage field")
    columns = status_grouping(records, group_by_field=group_by_field)
    applied = None
    if move is not None:
        if existing_status_patch is None:
            raise ValueError("kanban move requires the existing status patch contract")
        applied = existing_status_patch(move)
    return {"columns": columns, "group_by_field": group_by_field, "applied_move": applied}


def relationship_view(
    records: list[Mapping[str, Any]],
    *,
    field: str,
    value: Any,
) -> list[Mapping[str, Any]]:
    if not field:
        raise ValueError("relationship_view requires an authored field")
    return [record for record in records if _field(record, field) == value]


def portal_read_only_detail(
    record: Mapping[str, Any],
    *,
    visible_fields: list[str],
    mutation_controls: list[str] | None = None,
) -> dict[str, Any]:
    hidden = set(mutation_controls or ("edit", "patch", "delete", "status", "assign"))
    projected = {key: record[key] for key in visible_fields if key in record}
    return {
        "record": projected,
        "read_only": True,
        "mutation_controls": [],
        "suppressed_controls": sorted(hidden),
    }


def booking_staff_table(resources: list[Mapping[str, Any]]) -> dict[str, Any]:
    columns = ("name", "resource_key", "duration_minutes", "timezone", "status")
    rows = [{key: resource.get(key) for key in columns} for resource in resources]
    return {"presentation": "staff_table", "columns": list(columns), "rows": rows}


def booking_calendar(slots: list[Mapping[str, Any]]) -> dict[str, Any]:
    days: dict[str, list[Mapping[str, Any]]] = defaultdict(list)
    for slot in slots:
        start = str(slot.get("starts_at") or "")
        day = start[:10] if start else "unspecified"
        days[day].append({"starts_at": slot.get("starts_at"), "ends_at": slot.get("ends_at")})
    return {"presentation": "calendar", "days": dict(days)}
