"""XSD 要素定義パーサー。

XBRL タクソノミの XSD から ``xs:element`` 宣言をパースし、
concept のメタデータ（periodType, balance, abstract 等）を提供する。

典型的な使い方::

    from xbrl_core.schema.elements import parse_xsd_elements

    elements = parse_xsd_elements(xsd_bytes)
    elem = elements["NetSales"]
    print(elem.period_type)  # "duration"
    print(elem.balance)      # "credit"
"""

from __future__ import annotations

import logging
from dataclasses import dataclass

from lxml import etree

from xbrl_core.errors import XbrlParseError

logger = logging.getLogger(__name__)

# XSD 名前空間
_NS_XS = "http://www.w3.org/2001/XMLSchema"
# XBRL 属性拡張名前空間
_NS_XBRLI = "http://www.xbrl.org/2003/instance"


# ========== データモデル ==========


@dataclass(frozen=True, slots=True)
class ElementDefinition:
    """XSD の ``xs:element`` 宣言から抽出した concept 定義。

    Attributes:
        name: 要素名（ローカル名）。
        type_name: ``type`` 属性値（例: ``"xbrli:monetaryItemType"``）。
        period_type: ``xbrli:periodType`` 属性値（``"instant"`` | ``"duration"``）。
        balance: ``xbrli:balance`` 属性値（``"debit"`` | ``"credit"``）。
        abstract: abstract 要素かどうか。
        substitution_group: ``substitutionGroup`` 属性値。
        nillable: nillable かどうか。
    """

    name: str
    type_name: str | None
    period_type: str | None
    balance: str | None
    abstract: bool
    substitution_group: str | None
    nillable: bool


# ========== 公開 API ==========


def parse_xsd_elements(
    xsd_bytes: bytes,
    *,
    source_path: str | None = None,
) -> dict[str, ElementDefinition]:
    """XSD bytes から xs:element 宣言をパースする。

    Args:
        xsd_bytes: XSD ファイルのバイト列。
        source_path: エラーメッセージ用のソースファイルパス。

    Returns:
        要素名をキー、ElementDefinition を値とする辞書。

    Raises:
        XbrlParseError: XML パースに失敗した場合。
    """
    try:
        root = etree.fromstring(xsd_bytes)  # noqa: S320
    except etree.XMLSyntaxError as exc:
        source_label = source_path or "<bytes>"
        raise XbrlParseError(
            "XBRL_PARSE_010",
            f"Failed to parse XSD: {source_label}: {exc}",
            source=source_label,
        ) from exc

    result: dict[str, ElementDefinition] = {}
    tag_element = f"{{{_NS_XS}}}element"
    attr_period_type = f"{{{_NS_XBRLI}}}periodType"
    attr_balance = f"{{{_NS_XBRLI}}}balance"

    for elem in root.iter(tag_element):
        name = elem.get("name")
        if not name:
            continue

        type_name = elem.get("type")
        period_type = elem.get(attr_period_type)
        balance = elem.get(attr_balance)
        abstract_str = elem.get("abstract", "false")
        abstract = abstract_str in ("true", "1")
        substitution_group = elem.get("substitutionGroup")
        nillable_str = elem.get("nillable", "false")
        nillable = nillable_str in ("true", "1")

        result[name] = ElementDefinition(
            name=name,
            type_name=type_name,
            period_type=period_type,
            balance=balance,
            abstract=abstract,
            substitution_group=substitution_group,
            nillable=nillable,
        )

    logger.debug("XSD 要素定義パース: %d 要素", len(result))
    return result
