"""
init_research.py — Scaffold a new autoresearch-skill project directory.

Usage:
    python init_research.py --goal "..." --metric "..." --direction {maximize|minimize} \
        [--target "..."] [--max-iterations 10] [--output ./my-research/]
"""

import argparse
import math
import sys
import textwrap
from datetime import datetime
from pathlib import Path
from typing import Optional

RESEARCH_TEMPLATE = """\
# Research: {title}

## Goal
{goal}

## Success Metric
- **Metric:** {metric}
- **Target:** {target}
- **Direction:** {direction}

## Constraints
- **Max iterations:** {max_iterations}
- **Time budget per experiment:** 5 minutes
- **Pause for review every:** never
- **Evaluator:** {evaluator}
- **Keep policy:** {keep_policy}
- **Guard:** {guard}
- **Noise runs:** {noise_runs}
- **Min delta:** {min_delta}

## Current Approach
_Describe your current baseline here._

## Search Space
- **Allowed changes:** _Define what the agent can modify._
- **Forbidden changes:** _Define what must NOT change._

## Context & References
_Add relevant papers, docs, or URLs here._

---

## History
| # | Change | Metric | Result | Timestamp |
|---|--------|--------|--------|-----------|
| 0 | Baseline | TBD | -- | {date} |
"""

LOG_TEMPLATE = """\
# Research Log

> Auto-generated by init_research.py on {date}
> Goal: {goal}

---

"""

TSV_HEADER = "iteration\tmetric_value\tdelta\tdelta_pct\tstatus\tdescription\tevaluator_source\ttimestamp\n"
TSV_BASELINE = "0\tTBD\t-\t-\tbaseline\tInitial state\tagent\t{date}\n"


def goal_to_title(goal: str) -> str:
    """Convert a goal string to a short title (first 8 words, title-cased)."""
    words = goal.split()
    short = " ".join(words[:8])
    if len(words) > 8:
        short += "..."
    return short.title()


def parse_args() -> argparse.Namespace:
    parser = argparse.ArgumentParser(
        description="Scaffold a new autoresearch-skill project.",
        formatter_class=argparse.RawDescriptionHelpFormatter,
        epilog=textwrap.dedent("""\
            Example:
              python init_research.py \\
                --goal "Optimize sorting algorithm performance" \\
                --metric "execution_time_seconds" \\
                --direction minimize \\
                --target "< 0.5" \\
                --max-iterations 20 \\
                --output ./sort-research/
        """),
    )
    parser.add_argument("--goal", required=True, help="Research goal description.")
    parser.add_argument("--metric", required=True, help="Metric name to track (e.g. accuracy, execution_time_seconds).")
    parser.add_argument(
        "--direction",
        required=True,
        choices=["maximize", "minimize"],
        help="Whether to maximize or minimize the metric.",
    )
    parser.add_argument("--target", default="TBD", help="Target value or expression (e.g. '> 0.9', '< 0.5'). Default: TBD")
    parser.add_argument("--max-iterations", type=int, default=20, metavar="N", help="Maximum number of iterations. Default: 20")
    parser.add_argument("--output", default="./research/", metavar="PATH", help="Output directory. Default: ./research/")
    parser.add_argument("--evaluator", default=None, metavar="CMD",
        help="Evaluator command (e.g. 'python evaluate.py'). Must output JSON {pass:bool, score?:number}.")
    parser.add_argument("--keep-policy", default="score_improvement",
        choices=["score_improvement", "pass_only"],
        help="Keep policy: score_improvement (default) or pass_only.")
    parser.add_argument("--guard", default=None, metavar="CONDITION",
        help="Guard condition that must remain true (e.g. 'all unit tests pass'). Hard stop if violated.")
    parser.add_argument("--noise-runs", type=int, default=1, metavar="N",
        help="Number of runs to median over for noisy metrics. Default: 1")
    parser.add_argument("--min-delta", type=float, default=0.0, metavar="DELTA",
        help="Minimum improvement required to keep a change. Default: 0 (any improvement counts).")
    parser.add_argument("--force", action="store_true",
        help="Overwrite generated files in a non-empty output directory.")
    return parser.parse_args()


def validate_args(args: argparse.Namespace) -> None:
    if args.max_iterations < 1:
        print("Error: --max-iterations must be >= 1.", file=sys.stderr)
        raise SystemExit(1)
    if args.noise_runs < 1:
        print("Error: --noise-runs must be >= 1.", file=sys.stderr)
        raise SystemExit(1)
    if not math.isfinite(args.min_delta) or args.min_delta < 0:
        print("Error: --min-delta must be finite and >= 0.", file=sys.stderr)
        raise SystemExit(1)


def scaffold(goal: str, metric: str, direction: str, target: str, max_iterations: int, output: Path,
             evaluator: Optional[str] = None, keep_policy: str = "score_improvement",
              guard: Optional[str] = None, noise_runs: int = 1, min_delta: float = 0.0,
              force: bool = False) -> None:
    date = datetime.now().strftime("%Y-%m-%d")
    title = goal_to_title(goal)
    evaluator_str = f"`{evaluator}`" if evaluator else "_(none — agent judges manually)_"
    guard_str = guard if guard else "_(none)_"

    if output.exists() and any(output.iterdir()) and not force:
        raise FileExistsError(f"output directory '{output}' already exists and is not empty; use --force to overwrite generated files")

    output.mkdir(parents=True, exist_ok=True)

    # Create workspace subdirectory
    workspace = output / "workspace"
    workspace.mkdir(exist_ok=True)

    # Write research.md
    research_md = output / "research.md"
    research_md.write_text(
        RESEARCH_TEMPLATE.format(
            title=title,
            goal=goal,
            metric=metric,
            target=target,
            direction=direction,
            max_iterations=max_iterations,
            evaluator=evaluator_str,
            keep_policy=keep_policy,
            guard=guard_str,
            noise_runs=noise_runs,
            min_delta=min_delta,
            date=date,
        ),
        encoding="utf-8",
    )

    # Write research_log.md
    log_md = output / "research_log.md"
    log_md.write_text(LOG_TEMPLATE.format(date=date, goal=goal), encoding="utf-8")

    # Write autoresearch-results.tsv
    tsv_file = output / "autoresearch-results.tsv"
    tsv_file.write_text(TSV_HEADER + TSV_BASELINE.format(date=date), encoding="utf-8")

    # Print success message
    print(f"\nResearch project scaffolded at: {output.resolve()}")
    print(f"\nFiles created:")
    print(f"  {research_md.resolve()}")
    print(f"  {log_md.resolve()}")
    print(f"  {tsv_file.resolve()}")
    print(f"  {workspace.resolve()}/")
    print(f"\nNext steps:")
    print(f"  1. Open research.md and fill in 'Current Approach' and 'Search Space'.")
    print(f"  2. Add context (papers, docs, code) under 'Context & References'.")
    print(f"  3. Run your baseline experiment and record it in the History table.")
    print(f"  4. Start iterating: modify → measure → log → repeat.")
    print("  5. Run iterations only through the approved attended LitHermes root workflow.")


def main() -> None:
    args = parse_args()
    validate_args(args)
    output = Path(args.output)
    try:
        scaffold(
            goal=args.goal,
            metric=args.metric,
            direction=args.direction,
            target=args.target,
            max_iterations=args.max_iterations,
            output=output,
            evaluator=args.evaluator,
            keep_policy=args.keep_policy,
            guard=args.guard,
            noise_runs=args.noise_runs,
            min_delta=args.min_delta,
            force=args.force,
        )
    except FileExistsError as error:
        print(f"Error: {error}", file=sys.stderr)
        raise SystemExit(1) from None


if __name__ == "__main__":
    main()
