"""Supervisor (Lou) for periodic review of worker progress."""

import logging
import shutil
import subprocess
from pathlib import Path

from pywiggum.config import SupervisorConfig
from pywiggum.controls import Controls

logger = logging.getLogger(__name__)


class Supervisor:
    """Periodically reviews worker progress and sets hints via controls."""

    def __init__(self, config: SupervisorConfig, controls: Controls, work_dir: Path):
        self.config = config
        self.controls = controls
        self.work_dir = work_dir

    def should_review(self, current_iteration: int, current_task_iterations: int) -> bool:
        """Check if a supervisor review should run.

        Only called when a task is still in progress (not completed).
        Two triggers (both active):
        1. Every N global iterations
        2. After N failed attempts on the same task
        """
        # Trigger 1: periodic check-in
        if current_iteration > 0 and current_iteration % self.config.every_n_iterations == 0:
            return True

        # Trigger 2: repeated failures on the same task
        if current_task_iterations >= self.config.after_n_failed_attempts:
            return True

        return False

    def review(
        self,
        task_id: str,
        task_title: str,
        task_description: str,
        acceptance_criteria: list[str],
        attempt_count: int,
        kanban_path: str,
        log_tail: str,
        git_diff: str,
    ) -> str | None:
        """Run a supervisor review via claude -p.

        Returns:
            The hint text if one was produced, None otherwise.
        """
        if not shutil.which("claude"):
            logger.warning("[Supervisor] claude CLI not found, skipping review")
            return None

        prompt = self._build_prompt(
            task_id, task_title, task_description, acceptance_criteria,
            attempt_count, kanban_path, log_tail, git_diff,
        )

        logger.info(f"[Supervisor] Reviewing task {task_id} (attempt {attempt_count})")

        try:
            result = subprocess.run(
                ["claude", "-p", prompt],
                cwd=self.work_dir,
                capture_output=True,
                text=True,
                timeout=self.config.timeout,
            )
        except subprocess.TimeoutExpired:
            logger.warning(f"[Supervisor] Review timed out after {self.config.timeout}s")
            return None
        except Exception as e:
            logger.warning(f"[Supervisor] Review failed: {e}")
            return None

        if result.returncode != 0:
            logger.warning(f"[Supervisor] claude exited {result.returncode}: {result.stderr[:200]}")
            return None

        hint = self._extract_hint(result.stdout)
        if hint:
            logger.info(f"[Supervisor] Setting hint: {hint[:120]}...")
            self.controls.set_hint(hint)
        else:
            logger.info("[Supervisor] No hint needed")

        return hint

    def _build_prompt(
        self,
        task_id: str,
        task_title: str,
        task_description: str,
        acceptance_criteria: list[str],
        attempt_count: int,
        kanban_path: str,
        log_tail: str,
        git_diff: str,
    ) -> str:
        """Build the review prompt sent to claude -p."""
        criteria_str = "\n".join(f"- {c}" for c in acceptance_criteria) if acceptance_criteria else "(none)"

        return f"""You are a supervisor reviewing a coding agent's progress on a task.

## Current Task
- **ID**: {task_id}
- **Title**: {task_title}
- **Description**: {task_description}
- **Acceptance Criteria**:
{criteria_str}

## Status
- **Attempt count**: {attempt_count}
- **Kanban file**: {kanban_path}

## Recent git changes (git diff --stat HEAD~3..HEAD)
```
{git_diff[:2000]}
```

## Last 30 lines of wiggum.log
```
{log_tail}
```

## Your Job
Review the worker's progress. Look for common problems:
1. Did the worker do the code work but forget to update {kanban_path}?
2. Is the worker stuck in a loop or repeating the same mistake?
3. Is there an obvious fix or next step the worker is missing?

If you see an issue, respond with exactly:
HINT: <one or two sentences of actionable guidance for the worker>

If everything looks fine or you have no actionable advice, respond with exactly:
NO_HINT

Respond with ONLY one of the above. No other text."""

    def _extract_hint(self, response: str) -> str | None:
        """Parse the supervisor's response for a hint."""
        for line in response.strip().splitlines():
            line = line.strip()
            if line.upper().startswith("HINT:"):
                return line[5:].strip()
            if line.upper() == "NO_HINT":
                return None
        # If response doesn't match expected format, log and skip
        logger.warning(f"[Supervisor] Unexpected response format: {response[:200]}")
        return None
