"""Storage-route helpers based on DBNames records.

This module maps platform DBNames roles to physical SQL name candidates. It
does not infer business semantics or concrete metadata object names.
"""

from __future__ import annotations

from dataclasses import asdict, dataclass
from typing import Iterable

from .dbnames import DBNamesRecord


TABLE_ROLE_PREFIX = {
    "Reference": "_Reference",
    "ReferenceChngR": "_ReferenceChngR",
    "Document": "_Document",
    "DocumentChngR": "_DocumentChngR",
    "Enum": "_Enum",
    "InfoRg": "_InfoRg",
    "InfoRgChngR": "_InfoRgChngR",
    "AccumRg": "_AccumRg",
    "AccumRgChngR": "_AccumRgChngR",
    "AccumRgOpt": "_AccumRgOpt",
    "AccumRgT": "_AccumRgT",
    "AccRg": "_AccRg",
    "AccRgAT0": "_AccRgAT0",
    "AccRgCT": "_AccRgCT",
    "AccRgChngR": "_AccRgChngR",
    "AccRgOpt": "_AccRgOpt",
    "Const": "_Const",
    "ConstChngR": "_ConstChngR",
    "DocumentJournal": "_DocumentJournal",
    "Node": "_Node",
    "ScheduledJobs": "_ScheduledJobs",
    "BPr": "_BPr",
    "BPrPoints": "_BPrPoints",
    "BPrChngR": "_BPrChngR",
    "Task": "_Task",
    "TaskChngR": "_TaskChngR",
    "Acc": "_Acc",
    "AccSInf": "_AccSInf",
    "AccChngR": "_AccChngR",
    "CKinds": "_CKinds",
    "CKindsChngR": "_CKindsChngR",
    "IntegServiceSettings": "_IntegServiceSettings",
    "IntegServiceMsgBody": "_IntegServiceMsgBody",
    "IntegServiceExtMsgBody": "_IntegServiceExtMsgBody",
    "IntegChannelInQueue": "_IntegChannelInQueue",
    "IntegChannelOutQueue": "_IntegChannelOutQueue",
}


FIELD_ROLE_PREFIX = {
    "Fld": "_Fld",
}


STRUCTURAL_ROLES = {
    "VT",
    "LineNo",
    "ByDims",
    "ByField",
    "ByResource",
    "ByProperty",
    "TurnoverDt",
    "TurnoverCt",
    "Turnover",
}


@dataclass(frozen=True)
class StorageRoute:
    guid: str
    storage_role: str
    sql_number: int
    source: str
    route_kind: str
    physical_name_candidate: str | None
    note: str

    def to_dict(self) -> dict[str, object]:
        return asdict(self)


def storage_route(record: DBNamesRecord) -> StorageRoute:
    """Return the mechanical SQL route candidate for one DBNames record."""

    role = record.storage_role
    if role in TABLE_ROLE_PREFIX:
        return StorageRoute(
            guid=record.guid,
            storage_role=role,
            sql_number=record.sql_number,
            source=record.source,
            route_kind="table",
            physical_name_candidate=f"{TABLE_ROLE_PREFIX[role]}{record.sql_number}",
            note="table-like DBNames storage role",
        )
    if role in FIELD_ROLE_PREFIX:
        return StorageRoute(
            guid=record.guid,
            storage_role=role,
            sql_number=record.sql_number,
            source=record.source,
            route_kind="field",
            physical_name_candidate=f"{FIELD_ROLE_PREFIX[role]}{record.sql_number}",
            note="field DBNames storage role; value suffixes depend on type evidence",
        )
    if role in STRUCTURAL_ROLES:
        return StorageRoute(
            guid=record.guid,
            storage_role=role,
            sql_number=record.sql_number,
            source=record.source,
            route_kind="structural",
            physical_name_candidate=None,
            note="structural DBNames role; requires parent object/section context",
        )
    return StorageRoute(
        guid=record.guid,
        storage_role=role,
        sql_number=record.sql_number,
        source=record.source,
        route_kind="unknown",
        physical_name_candidate=None,
        note="unclassified DBNames storage role",
    )


def group_records_by_guid(records: Iterable[DBNamesRecord]) -> dict[str, list[DBNamesRecord]]:
    grouped: dict[str, list[DBNamesRecord]] = {}
    for record in records:
        grouped.setdefault(record.guid, []).append(record)
    return grouped


def storage_routes(records: Iterable[DBNamesRecord]) -> list[StorageRoute]:
    return [storage_route(record) for record in records]
