"""Eval bundle export — write results + trial artifacts to a directory.

Called by: eval.py
"""

from __future__ import annotations

import datetime
import hashlib
import json
import logging
import shutil
from collections import defaultdict
from pathlib import Path

logger = logging.getLogger(__name__)

_FILES_TO_COPY = [
    Path("agent") / "trajectory.json",
    Path("verifier") / "reward.json",
    Path("timing.json"),
]


def generate_run_id(
    skill_path: Path | None,
    agent_name: str,
    model_name: str,
    environment_type: str,
) -> str:
    """Generate a unique run ID from timestamp + hash of eval config."""
    ts = datetime.datetime.now().strftime("%Y%m%d-%H%M%S")
    h = hashlib.sha256(
        f"{skill_path}:{agent_name}:{model_name}:{environment_type}".encode()
    ).hexdigest()[:8]
    return f"{ts}-{h}"


def export_eval_bundle(
    export_dir: Path,
    eval_result_dict: dict,
    trials_dir: Path,
    run_id: str,
) -> None:
    """Bundle results and trial artifacts into a self-contained export directory.

    Only includes trial dirs tagged with the given run_id (via run_id.txt).

    Args:
        export_dir: Destination directory for the bundle.
        eval_result_dict: Evaluation results dict (serializable).
        trials_dir: Root trials directory to scan.
        run_id: Only export trials whose run_id.txt matches this value.

    Layout:
        export_dir/
        ├── results.json
        └── trials/
            └── <task_name>/
                └── run-<N>/
                    ├── trajectory.json
                    ├── reward.json
                    └── timing.json
    """
    if export_dir.exists():
        ts = datetime.datetime.now().strftime("%Y%m%d-%H%M%S")
        renamed = export_dir.with_name(f"{export_dir.name}.{ts}")
        export_dir.rename(renamed)
        logger.info(f"Existing export dir renamed to {renamed}")
    export_dir.mkdir(parents=True)

    # Write results summary
    (export_dir / "results.json").write_text(
        json.dumps(eval_result_dict, indent=2) + "\n"
    )

    if not trials_dir.exists():
        return

    # Find trial dirs matching this run's ID.
    # Supports two layouts:
    #   Flat:   trials_dir/<trial_name>/           (Harbor backend)
    #   Nested: trials_dir/<job_name>/<trial_name>/ (benchflow backend)
    task_runs: dict[str, list[Path]] = defaultdict(list)
    for child in sorted(trials_dir.iterdir()):
        if not child.is_dir():
            continue
        # Check flat layout (child is a trial dir)
        candidates = [child]
        # Also check nested layout (child is a job dir containing trial dirs)
        candidates.extend(
            sub for sub in sorted(child.iterdir()) if sub.is_dir()
        )
        for trial_dir in candidates:
            rid_file = trial_dir / "run_id.txt"
            if not rid_file.exists() or rid_file.read_text().strip() != run_id:
                continue
            name_file = trial_dir / "task_name.txt"
            if not name_file.exists():
                continue
            task_name = name_file.read_text().strip()
            if task_name:
                task_runs[task_name].append(trial_dir)

    # Copy relevant files into export layout
    trials_export = export_dir / "trials"
    for task_name, dirs in task_runs.items():
        for idx, trial_dir in enumerate(dirs, start=1):
            run_dir = trials_export / task_name / f"run-{idx}"
            run_dir.mkdir(parents=True, exist_ok=True)
            for rel in _FILES_TO_COPY:
                src = trial_dir / rel
                if src.exists():
                    dst = run_dir / rel.name
                    shutil.copy2(src, dst)
