"""Escalation handler — diagnoses failed tasks and creates fix tasks."""

from __future__ import annotations

import logging

import asyncpg
from redis.asyncio import Redis

from loom.bus.events import EventType
from loom.bus.publisher import publish_event
from loom.config import LoomConfig
from loom.graph import cache, store
from loom.graph.task import Priority, Task, TaskStatus
from loom.ids import task_id as gen_task_id

log = logging.getLogger(__name__)


async def handle_escalation(
    pool: asyncpg.Pool,
    redis: Redis,
    project_id: str,
    task_id: str,
    message: str,
    config: LoomConfig,
    project_dir: str | None = None,
) -> dict:
    """Process an escalation: diagnose and optionally create fix tasks.

    Flow:
    1. Load the failed/blocked task
    2. Run debug_failure skill with task context + escalation message
    3. If skill suggests new tasks: create them as children of the failed task
    4. Mark escalation as resolved
    5. Publish ESCALATION_RESOLVED event

    Returns a summary dict with diagnosis and created tasks.
    """
    # Dedup guard: skip if this task was recently escalated
    from loom.bus.channels import escalation_guard_key
    guard_key = escalation_guard_key(project_id, task_id)
    ttl = getattr(config.orchestration, 'escalation_dedup_ttl_seconds', 600)
    already_escalated = not await redis.set(guard_key, "1", nx=True, ex=ttl)
    if already_escalated:
        log.info("Escalation dedup: skipping duplicate for task %s", task_id)
        return {"task_id": task_id, "skipped": True, "reason": "dedup_guard"}

    # 1. Load the task
    task = await store.get_task(pool, task_id)

    # 2. Run the debug_failure skill
    diagnosis = await _run_diagnosis(
        task, message, config, pool, project_id, project_dir,
    )

    # 3. Create fix tasks if suggested
    created_tasks: list[str] = []
    suggested = diagnosis.get("suggested_tasks", [])
    if suggested:
        created_tasks = await _create_fix_tasks(
            pool, redis, project_id, task_id, suggested,
        )

    # 4. Resolve the escalation in Postgres
    async with pool.acquire() as conn:
        await conn.execute(
            """
            UPDATE escalations SET resolved = TRUE, resolved_at = NOW()
            WHERE task_id = $1 AND resolved = FALSE
            """,
            task_id,
        )

    # 5. Publish event
    await publish_event(
        redis, project_id, EventType.ESCALATION_RESOLVED, task_id,
        payload={
            "diagnosis": diagnosis.get("diagnosis", {}),
            "fix_tasks_created": len(created_tasks),
        },
    )

    return {
        "task_id": task_id,
        "diagnosis": diagnosis,
        "fix_tasks_created": created_tasks,
    }


async def _run_diagnosis(
    task: Task,
    escalation_message: str,
    config: LoomConfig,
    pool: asyncpg.Pool,
    project_id: str,
    project_dir: str | None,
) -> dict:
    """Run the debug_failure skill to diagnose the task failure.

    If the skill is not available or fails, returns a minimal diagnosis.
    """
    try:
        from loom.skills.loader import load_skill
        from loom.skills.runner import run_skill

        skill = load_skill("debug_failure", project_dir)
        inputs = {
            "task_title": task.title,
            "task_context": str(task.context),
            "error_message": escalation_message,
            "output": str(task.output),
        }
        return await run_skill(skill, inputs, config.skills, pool, project_id)

    except Exception:
        log.exception("debug_failure skill failed for task %s", task.id)
        return {
            "diagnosis": {
                "root_cause": f"Escalation: {escalation_message}",
                "category": "unknown",
                "confidence": "low",
            },
            "fix_steps": [],
            "suggested_tasks": [],
        }


async def _create_fix_tasks(
    pool: asyncpg.Pool,
    redis: Redis,
    project_id: str,
    parent_task_id: str,
    suggested_tasks: list[dict],
) -> list[str]:
    """Create child tasks from the diagnosis's suggested_tasks list."""
    created_ids: list[str] = []

    for td in suggested_tasks:
        title = td.get("title", "Fix task")
        context = td.get("context", "")
        priority_str = td.get("priority", "p1")
        done_when = td.get("done_when")

        try:
            priority = Priority(priority_str)
        except ValueError:
            priority = Priority.P1

        task = Task(
            id=gen_task_id(),
            project_id=project_id,
            title=title,
            status=TaskStatus.PENDING,
            priority=priority,
            parent_id=parent_task_id,
            context={"description": context, "source": "escalation_handler"},
            done_when=done_when,
        )

        created = await store.create_task(pool, task)
        await cache.sync_task(redis, created)
        await cache.add_to_ready_queue(redis, created)
        await publish_event(
            redis, project_id, EventType.TASK_CREATED, created.id,
        )

        created_ids.append(created.id)

    return created_ids
