"""Core registry for BCE code lookups."""

from __future__ import annotations

import json
import os
from typing import Any

DATA_DIR = os.path.join(os.path.dirname(__file__), "data")

_ALL_REGISTRIES: list[CodeRegistry] = []


class CodeRegistry:
    """A registry for a single BCE code type.

    Supports lookup by:
    - Full code: "jcc:m100" or "jcc:100"
    - Code suffix (part after prefix): "m100" or "100"
    - Value directly: "100"
    """

    def __init__(self, data_file: str, name: str):
        self.name = name
        path = os.path.join(DATA_DIR, data_file)
        with open(path, encoding="utf-8") as f:
            raw = json.load(f)
        self.prefix: str = raw["code_prefix"]
        self.codes: dict[str, dict[str, Any]] = raw["codes"]
        # Build reverse index: map all possible input forms to canonical keys
        self._index: dict[str, list[str]] = {}
        for key in self.codes:
            self._add_to_index(key, key)
            # 'm' prefix variant
            self._add_to_index(f"m{key}", key)
            # Full code forms
            self._add_to_index(f"{self.prefix}{key}", key)
            self._add_to_index(f"{self.prefix}m{key}", key)
            # For compound keys like "2003:01", also index "2003:m01" forms
            if ":" in key:
                parts = key.rsplit(":", 1)
                m_variant = f"{parts[0]}:m{parts[1]}"
                self._add_to_index(m_variant, key)
                self._add_to_index(f"{self.prefix}{m_variant}", key)

        _ALL_REGISTRIES.append(self)

    def _add_to_index(self, input_form: str, canonical_key: str):
        normalized = input_form.strip().lower()
        self._index.setdefault(normalized, [])
        if canonical_key not in self._index[normalized]:
            self._index[normalized].append(canonical_key)

    def _resolve(self, query: str) -> list[str]:
        """Resolve a query to matching canonical keys."""
        normalized = query.strip().lower()
        return self._index.get(normalized, [])

    def __call__(self, query: str, lang: str | None = None) -> dict[str, Any] | list[dict[str, Any]] | None:
        """Look up a code. Returns the entry dict, or a list if multiple matches.

        Args:
            query: Full code, code suffix, or value.
            lang: If set, return only the label for this language (e.g. "fr", "nl", "de", "en").
        """
        keys = self._resolve(query)
        if not keys:
            return None
        results = []
        for k in keys:
            entry = dict(self.codes[k])
            entry["_key"] = k
            entry["_code"] = f"{self.prefix}m{k}"
            if lang:
                label_key = f"label_{lang}"
                if label_key in entry:
                    entry = {"_key": k, "_code": entry["_code"], label_key: entry[label_key]}
            results.append(entry)
        return results[0] if len(results) == 1 else results

    def get(self, query: str, lang: str | None = None) -> dict[str, Any] | list[dict[str, Any]] | None:
        """Alias for __call__."""
        return self(query, lang)

    def all_keys(self) -> list[str]:
        """Return all canonical keys."""
        return list(self.codes.keys())


def lookup(query: str, lang: str | None = None) -> dict[str, Any] | None:
    """Global lookup across all code registries.

    Returns the match only if exactly one registry matches with exactly one result.
    Otherwise returns None (ambiguous).

    Args:
        query: Full code, code suffix, or value.
        lang: If set, return only the label for this language.
    """
    matches = []
    for registry in _ALL_REGISTRIES:
        result = registry(query, lang)
        if result is not None:
            if isinstance(result, list):
                matches.extend({"_registry": registry.name, **r} for r in result)
            else:
                matches.append({"_registry": registry.name, **result})
    if len(matches) == 1:
        return matches[0]
    return None
