#!/usr/bin/env python3
"""
Calculate PERT estimates from task files.

Usage:
    python3 estimate-effort.py spoq/epics/epic-name
    python3 estimate-effort.py spoq/epics/epic-name --json
"""

import sys
import json
from pathlib import Path

# Add lib directory to path for imports
lib_path = Path(__file__).parent.parent.parent / "lib"
sys.path.insert(0, str(lib_path))

from epic_utils import (
    load_tasks,
    compute_waves,
    group_waves,
    get_task_duration,
    calculate_pert_estimate,
    parse_duration
)


def estimate_epic(epic_path: Path) -> dict:
    """
    Calculate comprehensive effort estimates for an epic.

    Returns dict with per-wave and total estimates.
    """
    tasks = load_tasks(epic_path)
    valid_tasks = [t for t in tasks if "error" not in t]

    if not valid_tasks:
        return {"error": "No valid tasks found"}

    # Compute waves
    try:
        waves = compute_waves(valid_tasks)
        wave_groups = group_waves(waves)
    except ValueError as e:
        return {"error": f"Wave computation failed: {e}"}

    task_map = {t["id"]: t for t in valid_tasks}

    # Calculate per-wave estimates
    wave_estimates = {}
    total_optimistic = 0
    total_realistic = 0
    total_pessimistic = 0
    total_pert = 0

    for wave_num in sorted(wave_groups.keys()):
        task_ids = wave_groups[wave_num]
        wave_opt = 0
        wave_real = 0
        wave_pess = 0
        wave_pert = 0
        task_details = []

        for tid in task_ids:
            task = task_map.get(tid, {})
            estimate = task.get("estimate", {})

            opt = parse_duration(estimate.get("optimistic", "30m"))
            real = parse_duration(estimate.get("realistic", "1h"))
            pess = parse_duration(estimate.get("pessimistic", "2h"))
            pert = calculate_pert_estimate(task)

            wave_opt += opt
            wave_real += real
            wave_pess += pess
            wave_pert += pert

            task_details.append({
                "id": tid,
                "title": task.get("title", tid),
                "optimistic": opt,
                "realistic": real,
                "pessimistic": pess,
                "pert": pert
            })

        # For parallel execution, wave duration = max task duration
        max_pert = max(t["pert"] for t in task_details) if task_details else 0

        wave_estimates[wave_num] = {
            "task_count": len(task_ids),
            "total_optimistic": wave_opt,
            "total_realistic": wave_real,
            "total_pessimistic": wave_pess,
            "total_pert": wave_pert,
            "parallel_duration": max_pert,  # Time if all run in parallel
            "tasks": task_details
        }

        total_optimistic += wave_opt
        total_realistic += wave_real
        total_pessimistic += wave_pess
        total_pert += wave_pert

    # Calculate sequential vs parallel estimates
    sequential_duration = total_pert
    parallel_duration = sum(
        wave_estimates[w]["parallel_duration"]
        for w in wave_estimates
    )

    return {
        "epic_name": epic_path.name,
        "total_tasks": len(valid_tasks),
        "wave_count": len(wave_groups),
        "estimates": {
            "total_optimistic_hours": total_optimistic,
            "total_realistic_hours": total_realistic,
            "total_pessimistic_hours": total_pessimistic,
            "total_pert_hours": total_pert,
            "sequential_hours": sequential_duration,
            "parallel_hours": parallel_duration,
            "speedup_factor": sequential_duration / parallel_duration if parallel_duration > 0 else 1
        },
        "waves": wave_estimates
    }


def format_report(estimates: dict) -> str:
    """Format estimates as human-readable report."""
    lines = []

    if "error" in estimates:
        return f"Error: {estimates['error']}"

    lines.append("=" * 60)
    lines.append(f"EFFORT ESTIMATES: {estimates['epic_name']}")
    lines.append("=" * 60)
    lines.append("")

    # Summary
    est = estimates["estimates"]
    lines.append("SUMMARY")
    lines.append("-" * 40)
    lines.append(f"  Total tasks: {estimates['total_tasks']}")
    lines.append(f"  Total waves: {estimates['wave_count']}")
    lines.append("")
    lines.append(f"  Three-point estimates:")
    lines.append(f"    Optimistic:  {est['total_optimistic_hours']:.1f} hours")
    lines.append(f"    Realistic:   {est['total_realistic_hours']:.1f} hours")
    lines.append(f"    Pessimistic: {est['total_pessimistic_hours']:.1f} hours")
    lines.append(f"    PERT:        {est['total_pert_hours']:.1f} hours")
    lines.append("")
    lines.append(f"  Execution modes:")
    lines.append(f"    Sequential:  {est['sequential_hours']:.1f} hours")
    lines.append(f"    Parallel:    {est['parallel_hours']:.1f} hours")
    lines.append(f"    Speedup:     {est['speedup_factor']:.1f}x")
    lines.append("")

    # Per-wave breakdown
    lines.append("WAVE BREAKDOWN")
    lines.append("-" * 40)

    for wave_num in sorted(estimates["waves"].keys()):
        wave = estimates["waves"][wave_num]
        lines.append(f"  Wave {wave_num}: {wave['task_count']} tasks")
        lines.append(f"    Total (sequential): {wave['total_pert']:.1f}h")
        lines.append(f"    Duration (parallel): {wave['parallel_duration']:.1f}h")

        for task in wave["tasks"]:
            lines.append(f"      {task['id']}: {task['pert']:.1f}h "
                         f"({task['optimistic']:.1f}/{task['realistic']:.1f}/{task['pessimistic']:.1f})")
        lines.append("")

    # Recommendations
    lines.append("RECOMMENDATIONS")
    lines.append("-" * 40)

    if est["speedup_factor"] < 1.5:
        lines.append("  [!!] Low parallelism benefit - tasks are too sequential")
        lines.append("       Consider restructuring dependencies")
    elif est["speedup_factor"] >= 2.5:
        lines.append("  [OK] Good parallelism - significant speedup possible")
    else:
        lines.append("  [OK] Moderate parallelism - reasonable speedup")

    # Check for outlier tasks
    all_tasks = []
    for wave in estimates["waves"].values():
        all_tasks.extend(wave["tasks"])

    if all_tasks:
        avg_pert = sum(t["pert"] for t in all_tasks) / len(all_tasks)
        outliers = [t for t in all_tasks if t["pert"] > avg_pert * 2]
        if outliers:
            lines.append("")
            lines.append("  [!!] Large tasks detected (>2x average):")
            for t in outliers:
                lines.append(f"       {t['id']}: {t['pert']:.1f}h - consider breaking down")

    return "\n".join(lines)


def main():
    if len(sys.argv) < 2:
        print("Usage: estimate-effort.py <epic-path> [--json]", file=sys.stderr)
        sys.exit(1)

    epic_path = Path(sys.argv[1])
    json_output = "--json" in sys.argv

    if not epic_path.exists():
        print(f"Error: Epic path not found: {epic_path}", file=sys.stderr)
        sys.exit(1)

    estimates = estimate_epic(epic_path)

    if json_output:
        print(json.dumps(estimates, indent=2))
    else:
        report = format_report(estimates)
        print(report)

    if "error" in estimates:
        sys.exit(1)


if __name__ == "__main__":
    main()
