"""XBRL ファクトの型付きデータモデル。

ラベル情報 (:class:`LabelInfo`) と型付きファクト (:class:`LineItem`) を定義する。
"""

from __future__ import annotations

import enum
from dataclasses import dataclass
from decimal import Decimal
from typing import Literal

from xbrl_core.periods import Period
from xbrl_core.contexts import DimensionMember

__all__ = [
    "LabelSource",
    "LabelInfo",
    "LineItem",
]


class LabelSource(enum.Enum):
    """ラベルの情報源。

    Attributes:
        STANDARD: 標準タクソノミ由来。
        EXTENSION: 拡張（提出者別等）タクソノミ由来。
        FALLBACK: ラベルが見つからず local name を使用。
    """

    STANDARD = "standard"
    EXTENSION = "extension"
    FALLBACK = "fallback"


@dataclass(frozen=True, slots=True)
class LabelInfo:
    """解決されたラベル情報。

    Attributes:
        text: ラベルテキスト（例: ``"Net sales"``）。
        role: ラベルロール URI。
        lang: 言語コード（``"ja"`` / ``"en"``）。
        source: ラベルの情報源。
    """

    text: str
    role: str
    lang: str
    source: LabelSource


@dataclass(frozen=True, slots=True, kw_only=True)
class LineItem:
    """型付き・ラベル付きの XBRL Fact。

    :class:`~xbrl_core.parser.RawFact` +
    :class:`~xbrl_core.contexts.StructuredContext` +
    :class:`~xbrl_core.labels.LabelResolver` から生成される主要データ型。

    Attributes:
        concept: Clark notation の QName（例: ``"{ns}NetSales"``）。
        namespace_uri: 名前空間 URI。
        local_name: ローカル名（例: ``"NetSales"``）。
        labels: 解決されたラベル情報のタプル。
        value: 変換済みの値。数値 Fact は ``Decimal``、テキスト Fact は ``str``、
            nil Fact は ``None``。
        unit_ref: unitRef 属性値。テキスト Fact は ``None``。
        decimals: decimals 属性値。``int`` / ``"INF"`` / ``None``。
        context_id: contextRef 属性値。
        period: 期間情報。
        entity_id: Entity ID。
        dimensions: Dimension 情報。
        is_nil: xsi:nil が真かどうか。
        source_line: 元 XML の行番号。
        order: 元文書内の出現順。
    """

    concept: str
    namespace_uri: str
    local_name: str
    labels: tuple[LabelInfo, ...]
    value: Decimal | str | None
    unit_ref: str | None
    decimals: int | Literal["INF"] | None
    context_id: str
    period: Period
    entity_id: str
    dimensions: tuple[DimensionMember, ...]
    is_nil: bool
    source_line: int | None
    order: int

    def label(self, lang: str, role: str | None = None) -> str | None:
        """指定言語・ロールのラベルテキストを返す。

        Args:
            lang: 言語コード（例: ``"ja"``, ``"en"``）。
            role: ラベルロール URI。None の場合は言語のみでマッチ。

        Returns:
            ラベルテキスト。見つからなければ None。
        """
        for lbl in self.labels:
            if lbl.lang == lang and (role is None or lbl.role == role):
                return lbl.text
        return None
