"""Task management MCP tools for SPOQ."""

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

from spoq_server.server import mcp, project_root
from spoq_server import epic_utils


def _resolve_epic_path(epic_path: str) -> Path:
    """Resolve epic path relative to project root."""
    p = Path(epic_path)
    if not p.is_absolute():
        p = project_root() / p
    return p


VALID_STATUSES = {"pending", "in_progress", "qa", "rework", "completed", "failed"}


def _find_task_file(epic_path: Path, task_id: str) -> Path | None:
    """Find task YAML file by task_id prefix match."""
    tasks_dir = epic_path / "tasks"
    if not tasks_dir.exists():
        tasks_dir = epic_path

    # Try exact match first
    for pattern in [f"{task_id}.yml", f"{task_id}*.yml"]:
        matches = list(tasks_dir.glob(pattern))
        if matches:
            return matches[0]

    # Try searching all yml files for matching id field
    import yaml
    for yml_file in sorted(tasks_dir.glob("*.yml")):
        try:
            data = yaml.safe_load(yml_file.read_text())
            if isinstance(data, dict) and data.get("id") == task_id:
                return yml_file
        except Exception:
            continue

    return None


@mcp.tool()
def spoq_get_task(epic_path: str, task_id: str) -> str:
    """Get full details for a single task by ID.

    Args:
        epic_path: Path to epic directory.
        task_id: Task identifier (e.g., "01-setup").

    Returns JSON with the task's full YAML data.
    """
    try:
        eu = epic_utils
        resolved = _resolve_epic_path(epic_path)

        if not resolved.exists():
            return json.dumps({"error": f"Epic directory not found: {resolved}"})

        task_file = _find_task_file(resolved, task_id)
        if not task_file:
            return json.dumps({"error": f"Task '{task_id}' not found in epic at {resolved}"})

        task = eu.parse_task_yaml(task_file)
        task.pop("_source_file", None)
        return json.dumps(task, default=str)
    except Exception as e:
        return json.dumps({"error": str(e)})


@mcp.tool()
def spoq_update_task_status(epic_path: str, task_id: str, status: str, notes: str = "") -> str:
    """Update a task's status in-place in its YAML file.

    Args:
        epic_path: Path to epic directory.
        task_id: Task identifier.
        status: New status. Must be one of: pending, in_progress, qa, rework, completed, failed.
        notes: Optional progress notes to append.

    Returns JSON confirmation with updated fields.
    """
    try:
        if status not in VALID_STATUSES:
            return json.dumps({
                "error": f"Invalid status '{status}'. Must be one of: {', '.join(sorted(VALID_STATUSES))}"
            })

        resolved = _resolve_epic_path(epic_path)
        if not resolved.exists():
            return json.dumps({"error": f"Epic directory not found: {resolved}"})

        task_file = _find_task_file(resolved, task_id)
        if not task_file:
            return json.dumps({"error": f"Task '{task_id}' not found in epic at {resolved}"})

        import yaml

        content = task_file.read_text()
        data = yaml.safe_load(content)

        old_status = data.get("status", "unknown")
        data["status"] = status
        data["last_update"] = datetime.now(timezone.utc).strftime("%Y-%m-%dT%H:%M:%SZ")

        if notes:
            existing_notes = data.get("progress_notes", "")
            timestamp = datetime.now(timezone.utc).strftime("%Y-%m-%dT%H:%M:%SZ")
            new_note = f"[{timestamp}] {notes}"
            if existing_notes:
                data["progress_notes"] = f"{existing_notes}\n{new_note}"
            else:
                data["progress_notes"] = new_note

        # Write back using yaml.dump to preserve structure
        task_file.write_text(yaml.dump(data, default_flow_style=False, sort_keys=False, allow_unicode=True))

        result = {
            "task_id": task_id,
            "old_status": old_status,
            "new_status": status,
            "last_update": data["last_update"],
            "notes_added": bool(notes),
        }

        # Signal when the entire epic is now complete
        if status == "completed":
            all_tasks = epic_utils.load_tasks(resolved)
            valid = [t for t in all_tasks if "error" not in t]
            total = len(valid)
            done = sum(1 for t in valid if t.get("status") == "completed")
            result["epic_tasks_completed"] = done
            result["epic_tasks_total"] = total
            if done == total:
                result["epic_complete"] = True

        return json.dumps(result)
    except Exception as e:
        return json.dumps({"error": str(e)})


@mcp.tool()
def spoq_list_task_statuses(epic_path: str) -> str:
    """List all task statuses in an epic as a compact map.

    Args:
        epic_path: Path to epic directory.

    Returns JSON with {task_id: status} mapping and status counts.
    """
    try:
        eu = epic_utils
        resolved = _resolve_epic_path(epic_path)

        if not resolved.exists():
            return json.dumps({"error": f"Epic directory not found: {resolved}"})

        tasks = eu.load_tasks(resolved)

        statuses = {}
        counts = {}
        for task in tasks:
            if "error" in task:
                continue
            tid = task.get("id", "unknown")
            status = task.get("status", "pending")
            statuses[tid] = status
            counts[status] = counts.get(status, 0) + 1

        return json.dumps({
            "tasks": statuses,
            "counts": counts,
            "total": len(statuses),
        })
    except Exception as e:
        return json.dumps({"error": str(e)})
