"""Static facility level/slot mapping extracted from the source sheet.

The caller supplies an observed current facility level. Missing observations
are never replaced by the maximum, recipe requirement, or detected ring count.
"""
from __future__ import annotations

from functools import lru_cache
import json
from types import MappingProxyType

from .paths import resource_dir


@lru_cache(maxsize=8)
def _load(path, modified_ns, size):
    document = json.loads(path.read_text(encoding="utf-8"))
    if (type(document) is not dict or type(document.get("schema")) is not int or document["schema"] != 1
            or type(document.get("groups")) is not dict):
        raise ValueError("가공 시설 슬롯 표 형식이 올바르지 않습니다.")
    groups = {}
    for group, entry in document["groups"].items():
        if type(group) is not str or type(entry) is not dict or type(entry.get("levels")) is not dict:
            raise ValueError("가공 시설 슬롯 표 항목이 올바르지 않습니다.")
        levels = {}
        for level, capacity in entry["levels"].items():
            if (type(level) is not str or not level.isascii() or not level.isdigit()
                    or str(int(level)) != level or int(level) <= 0
                    or type(capacity) is not int or capacity <= 0):
                raise ValueError("가공 시설 레벨/슬롯 값이 올바르지 않습니다.")
            levels[int(level)] = capacity
        if not levels:
            raise ValueError("가공 시설 슬롯 표가 비어 있습니다.")
        groups[group] = MappingProxyType(levels)
    return MappingProxyType(groups)


def slot_capacity(group: str, level: int) -> int | None:
    """Return the exact sheet value, or None for unknown group/current level.

    No default7, formula extrapolation, numeric coercion or clamping is used.
    A changed resource file is reread; it is not cached beyond its file version.
    """
    if type(group) is not str or type(level) is not int or level <= 0:
        return None
    path = resource_dir() / "processing-facility-capacity.json"
    stat = path.stat()
    groups = _load(path, stat.st_mtime_ns, stat.st_size)
    return groups.get(group, {}).get(level)
