"""iXBRL フォーマット変換レジストリ。

iXBRL の ``format`` 属性で指定される変換ルール（ixt: / ixt-jpn: 等）を
管理する。標準フォーマットは組み込み済み。ロケール固有フォーマット
（例: ``ixt-jpn:kanjidate``）は ``register()`` で上位層が注入する。
"""

from __future__ import annotations

from collections.abc import Callable
from typing import Final

__all__ = ["FormatRegistry"]

FormatFunc = Callable[[str], str]
"""フォーマット変換関数の型。表示テキストを受け取り XBRL 値文字列を返す。"""


# ---------------------------------------------------------------------------
# 組み込みフォーマット関数
# ---------------------------------------------------------------------------


def _numdotdecimal(text: str) -> str:
    """ixt:numdotdecimal — カンマ除去、ドットを小数点。"""
    return text.replace(",", "").replace(" ", "").strip()


def _numcommadecimal(text: str) -> str:
    """ixt:numcommadecimal — ドット除去、カンマを小数点。"""
    return text.replace(" ", "").replace(".", "").replace(",", ".").strip()


def _booleantrue(_text: str) -> str:
    """ixt:booleantrue。"""
    return "true"


def _booleanfalse(_text: str) -> str:
    """ixt:booleanfalse。"""
    return "false"


# 組み込みフォーマット定義
_BUILTIN_FORMATS: Final[dict[str, FormatFunc]] = {
    "numdotdecimal": _numdotdecimal,
    "numcommadecimal": _numcommadecimal,
    "booleantrue": _booleantrue,
    "booleanfalse": _booleanfalse,
}


class FormatRegistry:
    """iXBRL フォーマット変換レジストリ。

    標準 ixt: フォーマットを組み込みで提供し、ロケール固有フォーマット
    を ``register()`` で追加できる。

    Example::

        registry = FormatRegistry()
        # ロケール固有フォーマットを追加
        registry.register("dateyearmonthdaycjk", my_cjk_date_func)

        # 変換
        result = registry.apply("ixt:numdotdecimal", "8,225")
        # → "8225"
    """

    def __init__(self) -> None:
        self._formats: dict[str, FormatFunc] = dict(_BUILTIN_FORMATS)

    def register(self, name: str, func: FormatFunc) -> None:
        """フォーマット変換関数を登録する。

        既存のフォーマットを上書きすることも可能。

        Args:
            name: フォーマット名（ローカル部分のみ、例: ``"dateyearmonthdaycjk"``）。
            func: 変換関数。表示テキストを受け取り XBRL 値文字列を返す。
        """
        self._formats[name.lower()] = func

    def apply(self, format_attr: str, display_text: str) -> str:
        """フォーマットを適用して XBRL 値文字列を返す。

        ``format_attr`` からプレフィクス（``"ixt:"`` 等）を除去し、
        登録済み関数にディスパッチする。未登録フォーマットは
        ``display_text`` をそのまま返す。

        Args:
            format_attr: ``format`` 属性値（例: ``"ixt:numdotdecimal"``）。
            display_text: 表示テキスト。

        Returns:
            XBRL 値文字列。

        Raises:
            ValueError: 登録済み関数が ValueError を送出した場合。
        """
        name = self._normalize(format_attr)
        func = self._formats.get(name)
        if func is None:
            return display_text.strip()
        return func(display_text)

    def has_format(self, format_attr: str) -> bool:
        """指定フォーマットが登録されているか。

        Args:
            format_attr: ``format`` 属性値。

        Returns:
            登録済みなら True。
        """
        name = self._normalize(format_attr)
        return name in self._formats

    @property
    def registered_names(self) -> frozenset[str]:
        """登録済みフォーマット名の集合。"""
        return frozenset(self._formats.keys())

    @staticmethod
    def _normalize(format_attr: str) -> str:
        """format 属性値を正規化する。プレフィクスを除去し小文字化。"""
        _, _, local = format_attr.rpartition(":")
        return local.lower() if local else format_attr.lower()
