"""
FORGE — Architecture & Build General
======================================
Fires parallel builder agents per story from a PRD.

Usage:
    from core.generals.forge import spawn_forge
    results = spawn_forge("/mnt/e/genesis-system/plans/PRD_VOICE_WIDGET.md", story_count=50)
"""

import json
import re
import uuid
from datetime import datetime, timezone
from pathlib import Path

REPO_ROOT = Path("/mnt/e/genesis-system")
SWARM_PROGRESS_DIR = REPO_ROOT / "data" / "swarm_progress"
HIVE_PROGRESS_DIR = REPO_ROOT / "hive" / "progress"

FORGE_BUILDER_PROMPT = """You are a FORGE builder agent for Genesis.

PRD: {prd_path}

Your task: Implement Story {story_index} of {total_stories}

Story title: {story_title}
Story description:
{story_body}

Instructions:
1. Read the full PRD file first to understand the system context
2. Implement ONLY this story — atomic, focused
3. Write black box tests (external behaviour)
4. Write white box tests (internal paths)
5. All tests must pass before marking story VERIFIED
6. Add VERIFICATION_STAMP comment to your implementation
7. Write output to: {output_file}

Constraints:
- NO SQLite — use PostgreSQL (Elestio) for persistence
- ALL files on E: drive only
- If tests fail: iterate up to 30 times before escalating
"""

FORGE_ARCHITECT_PROMPT = """You are the FORGE Architect for Genesis.

Mission: {mission}

Your role:
1. Design the full system architecture (diagrams, module structure)
2. Create a PRD with minimum 50 atomic stories
3. Each story must have acceptance criteria + test plan
4. Output the PRD to: {output_file}

Follow the PRD structure from GLOBAL_GENESIS_RULES.md Rule 4.
"""


def spawn_forge(prd_path: str, story_count: int = 50, mission: str = "") -> dict:
    """
    Spawn builder agents per story in a PRD.

    Parameters
    ----------
    prd_path : str
        Absolute path to the PRD file (or empty to trigger architect first)
    story_count : int
        Number of story-builder agents to launch (default 50)
    mission : str
        High-level mission (used if no PRD exists yet — triggers architect)

    Returns
    -------
    dict with swarm metadata
    """
    SWARM_PROGRESS_DIR.mkdir(parents=True, exist_ok=True)
    HIVE_PROGRESS_DIR.mkdir(parents=True, exist_ok=True)

    swarm_id = f"forge_{uuid.uuid4().hex[:8]}"
    output_dir = HIVE_PROGRESS_DIR / swarm_id
    output_dir.mkdir(parents=True, exist_ok=True)

    prd_file = Path(prd_path) if prd_path else None
    stories = []

    if prd_file and prd_file.exists():
        stories = _extract_stories(prd_file, story_count)
        print(f"[FORGE] Loaded {len(stories)} stories from {prd_file.name}")
    else:
        # Architect must create PRD first
        arch_output = output_dir / "PRD_GENERATED.md"
        arch_prompt = FORGE_ARCHITECT_PROMPT.format(
            mission=mission or prd_path,
            output_file=str(arch_output),
        )
        (output_dir / "architect_prompt.md").write_text(arch_prompt)
        print(f"[FORGE] No PRD found — architect prompt written to {arch_output}")
        # Generate synthetic story placeholders for now
        stories = [{"index": i + 1, "title": f"Story {i+1}", "body": ""} for i in range(story_count)]

    swarm_state = {
        "swarm_id": swarm_id,
        "general": "FORGE",
        "mission": mission or str(prd_path),
        "model": "minimax/minimax-01",
        "prd_path": str(prd_path),
        "agent_count": len(stories),
        "stories_total": len(stories),
        "stories_completed": 0,
        "stories_completed_this_hour": 0,
        "status": "running",
        "started_at": datetime.now(timezone.utc).isoformat(),
        "output_dir": str(output_dir),
    }

    state_file = SWARM_PROGRESS_DIR / f"{swarm_id}.json"

    # Write per-story builder prompts
    for story in stories:
        output_file = output_dir / f"story_{story['index']:03d}_output.md"
        prompt = FORGE_BUILDER_PROMPT.format(
            prd_path=prd_path,
            story_index=story["index"],
            total_stories=len(stories),
            story_title=story.get("title", f"Story {story['index']}"),
            story_body=story.get("body", "See PRD for details"),
            output_file=str(output_file),
        )
        (output_dir / f"story_{story['index']:03d}_prompt.md").write_text(prompt)

        # NOTE: Framework only — no live API calls.
        # Live: subprocess.Popen(["claude", "-p", prompt, "--output", str(output_file)])

    _save_state(state_file, swarm_state)
    print(f"[FORGE] Swarm {swarm_id} — {len(stories)} builder agents queued")
    return swarm_state


def spawn(prd_path: str = "", story_count: int = 50, mission: str = "") -> dict:
    """Alias for spawn_forge — used by genesis_hive.py router."""
    return spawn_forge(prd_path, story_count=story_count, mission=mission)


def _extract_stories(prd_file: Path, limit: int) -> list[dict]:
    """Parse Story blocks from a PRD Markdown file."""
    content = prd_file.read_text(encoding="utf-8", errors="replace")
    stories: list[dict] = []

    # Match ### Story N: Title sections
    pattern = re.compile(
        r"###\s+Story\s+(\d+)[:\s]+([^\n]+)\n(.*?)(?=###\s+Story\s+\d+|^##\s+|\Z)",
        re.DOTALL | re.MULTILINE,
    )
    for match in pattern.finditer(content):
        idx = int(match.group(1))
        title = match.group(2).strip()
        body = match.group(3).strip()
        stories.append({"index": idx, "title": title, "body": body})
        if len(stories) >= limit:
            break

    # If no structured stories found, generate placeholders
    if not stories:
        stories = [{"index": i + 1, "title": f"Story {i+1} from {prd_file.name}", "body": ""} for i in range(limit)]

    return stories


def _save_state(path: Path, state: dict) -> None:
    path.write_text(json.dumps(state, indent=2, default=str))
