"""財務諸表の階層表示モジュール。

PresentationTree の depth / ElementDefinition の abstract を使い、
財務データを「人間が見慣れた形式」で階層表示する。

LineItem は変更せず、表示時に階層情報と値データをマージする。
"""

from __future__ import annotations

from collections.abc import Sequence
from dataclasses import dataclass
from decimal import Decimal
from typing import TYPE_CHECKING

if TYPE_CHECKING:
    from rich.table import Table

from xbrl_core.models.financial import LineItem

__all__ = [
    "DisplayRow",
    "DisplayHint",
    "build_display_rows",
    "render_hierarchical_statement",
]


@dataclass(frozen=True, slots=True)
class DisplayRow:
    """表示用の1行。

    Attributes:
        label: 表示ラベル。
        value: 値。None はセクションヘッダー。
        concept: concept ローカル名。
        depth: インデント深度。
        is_abstract: セクションヘッダーかどうか。
        is_total: 合計行かどうか。
    """

    label: str
    value: Decimal | str | None
    concept: str
    depth: int
    is_abstract: bool
    is_total: bool


@dataclass(frozen=True, slots=True)
class DisplayHint:
    """概念に対する表示ヒント情報。

    PresentationTree + ElementDefinition から構築し、
    ``build_display_rows()`` に渡すことで階層表示を実現する。

    Attributes:
        concept: concept ローカル名。
        depth: インデント深度（0-based）。
        is_abstract: 抽象概念（セクションヘッダー）かどうか。
        is_total: 合計行かどうか。
        label: ラベルの上書き（None の場合は LineItem のラベルを使用）。
    """

    concept: str
    depth: int = 0
    is_abstract: bool = False
    is_total: bool = False
    label: str | None = None


def build_display_rows(
    items: Sequence[LineItem],
    *,
    hints: Sequence[DisplayHint] | None = None,
    label_lang: str = "en",
) -> list[DisplayRow]:
    """LineItem 群から表示行を生成する。

    Args:
        items: LineItem のシーケンス。
        hints: 階層表示のヒント。None の場合はフラット表示。
        label_lang: ラベルの言語コード。

    Returns:
        DisplayRow のリスト。
    """
    if hints is None:
        return [
            DisplayRow(
                label=item.label(label_lang) or item.local_name,
                value=item.value,
                concept=item.local_name,
                depth=0,
                is_abstract=False,
                is_total=False,
            )
            for item in items
        ]

    # LineItem を local_name でインデックス
    item_map: dict[str, LineItem] = {}
    for item in items:
        if item.local_name not in item_map:
            item_map[item.local_name] = item

    rows: list[DisplayRow] = []
    seen_concepts: set[str] = set()

    for hint in hints:
        if hint.is_abstract:
            label = hint.label or hint.concept
            rows.append(DisplayRow(
                label=label,
                value=None,
                concept=hint.concept,
                depth=hint.depth,
                is_abstract=True,
                is_total=False,
            ))
        else:
            li = item_map.get(hint.concept)
            if li is None:
                continue
            seen_concepts.add(hint.concept)
            label = hint.label or li.label(label_lang) or li.local_name
            rows.append(DisplayRow(
                label=label,
                value=li.value,
                concept=hint.concept,
                depth=hint.depth,
                is_abstract=False,
                is_total=hint.is_total,
            ))

    # hints にない LineItem を末尾に追加
    for item in items:
        if item.local_name not in seen_concepts:
            rows.append(DisplayRow(
                label=item.label(label_lang) or item.local_name,
                value=item.value,
                concept=item.local_name,
                depth=0,
                is_abstract=False,
                is_total=False,
            ))

    return rows


def render_hierarchical_statement(
    items: Sequence[LineItem],
    *,
    hints: Sequence[DisplayHint] | None = None,
    title: str | None = None,
    label_lang: str = "en",
) -> Table:
    """階層表示の Rich Table を返す。

    Args:
        items: LineItem のシーケンス。
        hints: 階層表示のヒント。
        title: テーブルタイトル。
        label_lang: ラベルの言語コード。

    Returns:
        Rich Table オブジェクト。

    Raises:
        ImportError: rich がインストールされていない場合。
    """
    try:
        from rich.table import Table as RichTable
    except ImportError:
        raise ImportError(
            "rich is required. Install with: pip install xbrl-core[display]"
        ) from None

    display_rows = build_display_rows(items, hints=hints, label_lang=label_lang)

    table = RichTable(title=title, title_style="bold", show_lines=False)
    table.add_column("Label", style="cyan", min_width=20)
    table.add_column("Amount", justify="right", style="green", min_width=20)
    table.add_column("concept", style="dim", no_wrap=True)

    for row in display_rows:
        indent = "  " * row.depth
        label = f"{indent}{row.label}"

        if row.is_abstract:
            table.add_row(
                f"[bold cyan]{label}[/bold cyan]",
                "",
                f"[dim]{row.concept}[/dim]",
            )
        elif row.is_total:
            if isinstance(row.value, Decimal):
                value_str = f"[bold green]{row.value:,}[/bold green]"
            else:
                value_str = ""
            table.add_row(
                f"[bold]{label}[/bold]",
                value_str,
                row.concept,
            )
        else:
            if isinstance(row.value, Decimal):
                value_str = f"{row.value:,}"
            elif row.value is None:
                value_str = "\u2014"
            else:
                value_str = str(row.value)
            table.add_row(label, value_str, row.concept)

    return table
