# #region MergeSpec [C:2] [TYPE Module]
# @LAYER Infra

# #region merge_spec [C:2] [TYPE Module]
# @LAYER Infra

import sys
from datetime import datetime
from pathlib import Path

REVIEW_PROMPT = (
    "Another LLM created this feature package. Your task: conduct an independent "
    "orthogonal spec review. Evaluate readiness, find contradictions, gaps, "
    "implementation risks, and prepare a structured report with corrections. "
    "Focus on spec review, not rewriting the implementation."
)

# Canonical artifact order for the merged output.
# Each stage: (match_type, value, section_label)
# match_type "exact" = exact filename match
# match_type "prefix" = directory prefix — matches all files under that dir
CANONICAL_MD_STAGES = (
    # Layer 1: Requirements & UX narrative
    ("exact",  "spec.md",            "SPEC — Feature Specification"),
    ("exact",  "ux_reference.md",    "UX REFERENCE — Interaction Narrative"),
    ("prefix", "checklists/",        "CHECKLISTS — Requirements Quality"),

    # Layer 2: UX Design (from /speckit.ux)
    ("exact",  "contracts/ux/alternatives.md",    "UX ALTERNATIVES — Design Space Explored"),
    ("exact",  "contracts/ux/decisions.md",       "UX DECISIONS — Final Choices"),
    ("exact",  "contracts/ux/screen-models.md",   "UX SCREEN MODELS — Model Inventory"),
    ("exact",  "contracts/ux/api-ux.md",          "UX API CONTRACT — Endpoints & Shapes"),
    ("prefix", "contracts/ux/",        "UX DESIGN — Per-Screen Contracts"),
    ("exact",  "contracts/ux/design-tokens.md",   None),  # force-first within prefix

    # Layer 3: Implementation Plan
    ("exact",  "plan.md",            "PLAN — Implementation Plan"),
    ("exact",  "research.md",        "RESEARCH — Technical Decisions"),
    ("exact",  "data-model.md",      "DATA MODEL — Entities & Relations"),
    ("prefix", "contracts/",         "CONTRACTS — Module & Function Contracts"),
    ("exact",  "quickstart.md",      "QUICKSTART — Dev Onboarding"),

    # Layer 4: Traceability
    ("exact",  "traceability.md",    "TRACEABILITY — Requirements Matrix"),

    # Layer 5: Execution
    ("exact",  "tasks.md",           "TASKS — Implementation Tasks"),
)

ORDER_HINT = (
    "Artifact order: spec → ux_reference → checklists → "
    "UX (alternatives → decisions → screen-models → api-ux → per-screen → design-tokens) → "
    "plan → research → data-model → contracts → quickstart → traceability → tasks → remaining."
)


def relative_key(path: Path, root: Path) -> str:
    return path.relative_to(root).as_posix()


def ordered_markdown_files(target_dir: Path) -> list[Path]:
    """Order markdown files according to CANONICAL_MD_STAGES."""
    markdown_files = [path for path in target_dir.rglob("*.md") if path.is_file()]
    remaining = {relative_key(path, target_dir): path for path in markdown_files}

    ordered: list[Path] = []
    # Track which stages have already been matched to avoid duplicates
    seen = set()

    for stage_type, stage_value, _section_label in CANONICAL_MD_STAGES:
        if stage_type == "exact":
            # Exact: only match if the file exists and hasn't been collected yet
            rel = f"contracts/ux/{stage_value}" if stage_value.startswith("contracts/ux/") else stage_value
            if stage_value.startswith("contracts/ux/"):
                path = remaining.pop(stage_value, None)
            else:
                path = remaining.pop(stage_value, None)
            if path is not None and path not in seen:
                ordered.append(path)
                seen.add(path)
            continue

        # Prefix: match all files whose relative path starts with stage_value
        stage_matches = sorted(
            [
                path
                for rel_path, path in remaining.items()
                if rel_path.startswith(stage_value)
            ],
            key=lambda p: relative_key(p, target_dir),
        )
        for path in stage_matches:
            if path not in seen:
                ordered.append(path)
                seen.add(path)
                rel = relative_key(path, target_dir)
                remaining.pop(rel, None)

    # Remaining files — append at end
    remaining_paths = sorted(remaining.values(), key=lambda p: relative_key(p, target_dir))
    for path in remaining_paths:
        if path not in seen:
            ordered.append(path)

    return ordered


def merge_specs(feature_number: str) -> str | None:
    """Merge all spec artifacts for a feature into one review file."""
    specs_dir = Path("specs")
    if not specs_dir.exists():
        print("Error: 'specs' directory not found.")
        return None

    # Find directory starting with feature number
    target_dir = None
    for item in specs_dir.iterdir():
        if item.is_dir() and item.name.startswith(f"{feature_number}-"):
            target_dir = item
            break

    if not target_dir:
        print(f"Error: No directory found for feature number '{feature_number}' in 'specs/'.")
        return None

    feature_name = target_dir.name
    now = datetime.now().strftime("%Y%m%d-%H%M%S")
    output_filename = f"{feature_name}-{now}.md"

    content_blocks = [
        REVIEW_PROMPT,
        "",
        "=" * 80,
        ORDER_HINT,
        f"Feature: {feature_name}",
        f"Generated: {datetime.now().isoformat()}",
        "=" * 80,
        "",
    ]

    files_to_merge = ordered_markdown_files(target_dir)

    for file_path in files_to_merge:
        relative_path = file_path.relative_to(target_dir)
        try:
            content = file_path.read_text(encoding="utf-8")
        except Exception as e:
            print(f"Skipping {file_path}: {e}")
            continue

        # Determine section label
        section_label = str(relative_path)
        for stage_type, stage_value, label in CANONICAL_MD_STAGES:
            if label is None:
                continue
            if stage_type == "exact" and str(relative_path) == stage_value:
                section_label = label
                break
            if stage_type == "prefix" and str(relative_path).startswith(stage_value):
                section_label = f"{label} — {relative_path.name}"
                break

        content_blocks.append("")
        content_blocks.append("-" * 60)
        content_blocks.append(f"## {section_label}")
        content_blocks.append(f"Source: {relative_path}")
        content_blocks.append("-" * 60)
        content_blocks.append("")
        content_blocks.append(content)
        content_blocks.append("")

    # Summary
    content_blocks.append("")
    content_blocks.append("=" * 80)
    content_blocks.append(f"Files merged: {len(files_to_merge)}")
    content_blocks.append("=" * 80)

    merged = "\n".join(content_blocks)
    output_filename = output_filename
    Path(output_filename).write_text(merged, encoding="utf-8")

    print(f"Successfully created: {output_filename} ({len(files_to_merge)} files)")
    return output_filename


if __name__ == "__main__":
    if len(sys.argv) < 2:
        print("Usage: python merge_spec.py <feature_number>")
        sys.exit(1)

    merge_specs(sys.argv[1])

# #endregion merge_spec

# #endregion MergeSpec
