"""
Story-level pipeline state management.

story_pipeline.json is the source of truth for story-level stages (S1-S6)
and per-episode preparation/review state.

Structure:
{
  "project_type": "story_adaptation",  # "story_adaptation" | "sketch_channel"
  "S1-ingest": "001",        # iteration selected (or null)
  "S2-bible": "002",
  "S3-style": "001",
  "S4-title": "001",
  "S5-assets": "complete",   # "complete" when all assets selected, else null
  "S6-episodes": "001",      # skipped for sketch_channel
  "episodes": {
    "001": {"prepared": "001", "reviewed": null},
    "002": {"prepared": null, "reviewed": null}
  }
}
"""

import json
from pathlib import Path
from typing import Optional


# Ordered list of story-level pipeline stages
STORY_STAGES = [
    "S1-ingest",
    "S2-bible",
    "S3-style",
    "S4-title",
    "S5-assets",
    "S6-episodes",
]


def load_story_pipeline(story_path: Path, project_type: str = None) -> dict:
    """Load story_pipeline.json. Create with all-null if missing.

    Args:
        story_path: Path to project directory
        project_type: If creating new, set project_type ("story_adaptation" or "sketch_channel")
    """
    pipeline_file = story_path / "story_pipeline.json"

    if pipeline_file.exists():
        with open(pipeline_file) as f:
            data = json.load(f)
        # Migrate old formats to new
        original = json.dumps(data, sort_keys=True)
        _migrate_pipeline(data)
        if json.dumps(data, sort_keys=True) != original:
            save_story_pipeline(story_path, data)
        return data

    # Create default
    pipeline = {stage: None for stage in STORY_STAGES}
    pipeline["project_type"] = project_type or "story_adaptation"
    pipeline["episodes"] = {}
    save_story_pipeline(story_path, pipeline)
    return pipeline


def get_project_type(pipeline: dict) -> str:
    """Get project type from pipeline state.

    Returns:
        "story_adaptation" or "sketch_channel"
    """
    return pipeline.get("project_type", "story_adaptation")


def _migrate_pipeline(data: dict) -> dict:
    """Migrate old stage names to new if needed."""
    changed = False

    # Migration: S4-characters → S5-characters → S5-assets
    old_char_keys = ["S4-characters", "S5-characters"]
    for old_key in old_char_keys:
        if old_key in data:
            data.pop(old_key)
            changed = True

    # Migration: S5-episodes → S6-episodes
    if "S5-episodes" in data and "S6-episodes" not in data:
        data["S6-episodes"] = data.pop("S5-episodes")
        changed = True
    elif "S5-episodes" in data and "S6-episodes" in data:
        data.pop("S5-episodes")
        changed = True

    # Ensure S4-title exists
    if "S4-title" not in data:
        data["S4-title"] = None
        changed = True

    # Ensure S5-assets exists
    if "S5-assets" not in data:
        data["S5-assets"] = None
        changed = True

    return data


def save_story_pipeline(story_path: Path, pipeline: dict) -> None:
    """Save story_pipeline.json."""
    pipeline_file = story_path / "story_pipeline.json"
    with open(pipeline_file, "w") as f:
        json.dump(pipeline, f, indent=2)
        f.write("\n")


def find_next_story_stage(pipeline: dict) -> Optional[str]:
    """Find first story stage not completed (null value).

    For sketch_channel projects, S6-episodes is skipped (sketches are
    written independently, not broken from a long story).

    Returns:
        Next stage name or None if all story stages complete.
    """
    is_sketch = get_project_type(pipeline) == "sketch_channel"
    for stage in STORY_STAGES:
        if is_sketch and stage == "S6-episodes":
            continue
        if pipeline.get(stage) is None:
            return stage
    return None


def get_episode_state(pipeline: dict, episode: str) -> dict:
    """Get state for a specific episode.

    Returns:
        {"prepared": "001" or None, "reviewed": "001" or None}
    """
    episodes = pipeline.get("episodes", {})
    return episodes.get(episode, {"prepared": None, "reviewed": None})


def set_episode_state(pipeline: dict, episode: str, key: str, value: str) -> None:
    """Update episode state (prepared or reviewed).

    Args:
        pipeline: Pipeline dict (modified in place)
        episode: Episode number (e.g. "001")
        key: "prepared" or "reviewed"
        value: Iteration number
    """
    if "episodes" not in pipeline:
        pipeline["episodes"] = {}
    if episode not in pipeline["episodes"]:
        pipeline["episodes"][episode] = {"prepared": None, "reviewed": None}
    pipeline["episodes"][episode][key] = value


def get_episodes_from_breakdown(story_path: Path, pipeline: dict) -> list:
    """Read episode list from the selected S6-episodes breakdown.

    For sketch_channel projects, discovers episodes from numbered directories.

    Returns:
        List of episode dicts from episodes.json, or empty list.
    """
    if get_project_type(pipeline) == "sketch_channel":
        return _discover_sketch_episodes(story_path)

    episodes_iter = pipeline.get("S6-episodes")
    if not episodes_iter:
        return []

    episodes_file = story_path / "S6-episodes" / episodes_iter / "episodes.json"
    if not episodes_file.exists():
        return []

    with open(episodes_file) as f:
        data = json.load(f)

    return data.get("episodes", [])


def _discover_sketch_episodes(story_path: Path) -> list:
    """Discover sketch episodes from numbered directories (001, 002, ...).

    Reads brief.txt or 01-story/001/story.md for title if available.
    """
    episodes = []
    for d in sorted(story_path.iterdir()):
        if not d.is_dir() or not d.name.isdigit():
            continue
        ep_num = int(d.name)
        title = ""
        # Try to get title from brief.txt first line
        brief = d / "brief.txt"
        if brief.exists():
            first_line = brief.read_text().strip().split("\n")[0]
            # Strip leading "# " or "EPISODE N: "
            title = first_line.lstrip("# ").strip()
            if title.upper().startswith("EPISODE"):
                parts = title.split(":", 1)
                title = parts[1].strip() if len(parts) > 1 else title
        else:
            story_md = d / "01-story" / "001" / "story.md"
            if story_md.exists():
                first_line = story_md.read_text().strip().split("\n")[0]
                title = first_line.lstrip("# ").strip()

        episodes.append({
            "number": ep_num,
            "title": title,
            "grid_layout": "3x3",
            "clip_duration": "5s",
        })
    return episodes


def format_story_status(story_path: Path, pipeline: dict) -> str:
    """Format story pipeline status as a readable string."""
    ptype = get_project_type(pipeline)
    is_sketch = ptype == "sketch_channel"
    label = "Sketch Channel" if is_sketch else "Story Pipeline"
    lines = [f"{label} Status:", ""]

    # Story stages
    for stage in STORY_STAGES:
        if is_sketch and stage == "S6-episodes":
            lines.append(f"  {stage}: (skipped — sketch channel)")
            continue
        value = pipeline.get(stage)
        if value:
            lines.append(f"  {stage}: {value} ✓")
        else:
            lines.append(f"  {stage}: —")

    # S5-assets detail
    plan_file = story_path / "S5-assets" / "assets_plan.json"
    if plan_file.exists():
        try:
            from story_stages.stage_s5_assets import get_asset_status
            lines.append("")
            lines.append(get_asset_status(story_path))
        except ImportError:
            pass

    # Episodes
    episodes = pipeline.get("episodes", {})
    if episodes:
        lines.append("")
        lines.append("Episodes:")
        for ep_num in sorted(episodes.keys()):
            ep = episodes[ep_num]
            prep = ep.get("prepared")
            rev = ep.get("reviewed")
            prep_str = f"prepared={prep}" if prep else "not prepared"
            rev_str = f"reviewed={rev}" if rev else "not reviewed"
            lines.append(f"  {ep_num}: {prep_str}, {rev_str}")

    # Next step
    next_stage = find_next_story_stage(pipeline)
    if next_stage:
        lines.append("")
        lines.append(f"Next: {next_stage}")
    else:
        lines.append("")
        lines.append("All story stages complete. Use prepare-episode to set up episodes.")

    return "\n".join(lines)
