"""
Relation triplet parser.

Reads structured :class:`RelationMeta` objects from relation markdown
files in ``output/relations/``.

File format::

    # Subject — predicate — Object

    ## Subject
    Subject Entity Title

    ## Predicate
    predicate phrase

    ## Object
    Object Entity Title

    ## Relation Type
    constrains

    ## VSM Channel
    S1 → S2

    ## Evidence
    Book I, Chapter 3: "..."

    ## Feedback Role
    Part of the Market Expansion loop: ...
"""

from __future__ import annotations

import logging
import re
from pathlib import Path
from typing import List, Optional, Sequence

from markitect.core.parser import parse_markdown_to_ast
from markitect.core.section_tree import (
    build_section_tree,
    extract_section_text,
    slugify,
)
from .relation_models import RelationMeta

logger = logging.getLogger(__name__)


def _find_h2(tree_root: dict, slug: str) -> Optional[dict]:
    for child in tree_root.get("children", []):
        if child["level"] == 2 and child["slug"] == slug:
            return child
    return None


def _section_text(root: dict, slug: str) -> str:
    node = _find_h2(root, slug)
    return extract_section_text(node).strip() if node else ""


def _slug_from_title(title: str) -> str:
    """Convert entity title to slug (same as slugify used in entity_parser)."""
    return slugify(title)


def parse_relation_file(path: Path) -> RelationMeta:
    """Parse a single relation markdown file into :class:`RelationMeta`.

    Raises:
        ValueError: If required sections are missing.
    """
    content = path.read_text(encoding="utf-8")
    tokens = parse_markdown_to_ast(content)
    tree = build_section_tree(tokens)

    # Find H1
    h1 = next(
        (c for c in tree["children"] if c["level"] == 1),
        None,
    )
    if h1 is None:
        raise ValueError(f"No H1 heading in {path}")

    root = h1

    subject = _section_text(root, "subject")
    predicate = _section_text(root, "predicate")
    obj = _section_text(root, "object")
    relation_type = _section_text(root, "relation_type")
    vsm_channel = _section_text(root, "vsm_channel")
    evidence = _section_text(root, "evidence")
    feedback_role = _section_text(root, "feedback_role")

    if not subject:
        raise ValueError(f"Missing ## Subject in {path}")
    if not predicate:
        raise ValueError(f"Missing ## Predicate in {path}")
    if not obj:
        raise ValueError(f"Missing ## Object in {path}")

    subject_slug = _slug_from_title(subject)
    object_slug = _slug_from_title(obj)

    # Derive canonical slug from file stem
    slug = path.stem

    return RelationMeta(
        slug=slug,
        subject=subject,
        subject_slug=subject_slug,
        predicate=predicate,
        object=obj,
        object_slug=object_slug,
        relation_type=relation_type,
        vsm_channel=vsm_channel,
        evidence=evidence,
        feedback_role=feedback_role,
        source_path=str(path),
    )


def parse_relations_directory(
    directory: Path,
) -> List[RelationMeta]:
    """Parse all relation files in *directory*.

    Malformed files are skipped with a warning.
    """
    relations: List[RelationMeta] = []
    for md_file in sorted(directory.glob("*.md")):
        try:
            relations.append(parse_relation_file(md_file))
        except Exception as exc:
            logger.warning("Skipping relation file %s: %s", md_file.name, exc)
    return relations
