"""Auto-fix execution endpoints for tool issues."""

import asyncio
from typing import Any

import structlog
from fastapi import APIRouter
from pydantic import BaseModel, Field

from proxym.tools import ToolRegistry

logger = structlog.get_logger()
router = APIRouter(tags=["tools"])

_AUTO_FIX_ACTIONS = {"install", "start_container", "start_vm"}
_HUMAN_FIX_ACTIONS = {"info", "config"}


class AutoFixRequest(BaseModel):
    tool_name: str = Field(..., description="Tool name to fix")
    fix_action: str = Field(..., description="Action type: install, config, start_container")
    command: str = Field("", description="Command to execute (optional)")


@router.post("/autofix")
async def execute_autofix(req: AutoFixRequest) -> dict[str, Any]:
    """Execute an automatic fix for a tool issue.

    Attempts to auto-fix: install missing binaries, start containers, etc.
    If human action is required, creates a ticket assigned to the default user.
    """
    result = {
        "tool": req.tool_name,
        "action": req.fix_action,
        "executed": False,
        "output": "",
        "error": "",
        "ticket_created": None,
    }

    # Determine if this fix can be auto-executed
    auto_executable = req.fix_action in ("install", "start_container", "start_vm")
    requires_human = req.fix_action in ("info", "config")

    if requires_human:
        # Create ticket for human action
        ticket = _create_human_action_ticket(req.tool_name, req.fix_action, req.command)
        result["ticket_created"] = ticket.summary() if ticket else None
        result["error"] = f"Fix requires human action. Ticket created: {ticket.id if ticket else 'failed'}"
        return result

    if not auto_executable:
        result["error"] = f"Unknown fix action: {req.fix_action}"
        return result

    # Execute the fix
    try:
        cmd = req.command
        if req.fix_action == "start_container":
            cmd = cmd or "docker compose up -d"
        elif not cmd:
            result["error"] = f"No {req.fix_action} command provided"
            return result

        timeout = {"install": 300, "start_vm": 60}.get(req.fix_action, 120)
        proc = await asyncio.create_subprocess_shell(
            cmd,
            stdout=asyncio.subprocess.PIPE,
            stderr=asyncio.subprocess.PIPE,
        )
        stdout, stderr = await asyncio.wait_for(proc.communicate(), timeout=timeout)
        result["output"] = stdout.decode() if stdout else ""
        result["error"] = stderr.decode() if stderr else ""
        result["exit_code"] = proc.returncode
        result["executed"] = proc.returncode == 0

    except asyncio.TimeoutError:
        result["error"] = "Fix execution timed out"
    except Exception as exc:
        result["error"] = f"Fix execution failed: {exc}"

    return result


@router.post("/autofix/bulk")
async def bulk_autofix() -> dict[str, Any]:
    """Run auto-fix for all degraded tools that support automatic fixes."""
    from proxym.config import get_settings
    from proxym.dashboard.tools._health import (
        _health_diag_base, _apply_provider_health,
        _apply_runtime_health, _finalize_health_status,
    )
    settings = get_settings()
    configured_providers = settings.available_providers()
    tool_providers = settings.tool_providers
    reg = ToolRegistry.get()

    results = []
    executed = 0
    failed = 0
    human_required = 0

    for tool in reg.list_tools():
        diag = _health_diag_base(tool, tool_providers)
        _apply_provider_health(diag, configured_providers)
        _apply_runtime_health(diag, tool)
        _finalize_health_status(diag)

        if diag["status"] != "ok" and diag["fixes"]:
            for fix in diag["fixes"]:
                outcome = await _process_bulk_fix(tool.name, fix)
                results.append(outcome["payload"])
                executed += outcome["executed"]
                failed += outcome["failed"]
                human_required += outcome["human_required"]

    return {
        "total_tools": len(reg.list_tools()),
        "executed": executed,
        "failed": failed,
        "human_required": human_required,
        "results": results,
    }


async def _process_bulk_fix(tool_name: str, fix: dict[str, Any]) -> dict[str, Any]:
    """Handle a single fix entry from bulk auto-fix."""
    action = fix.get("action", "")
    label = fix.get("label", "")

    if action in _AUTO_FIX_ACTIONS:
        try:
            req = AutoFixRequest(
                tool_name=tool_name,
                fix_action=action,
                command=fix.get("command", ""),
            )
            result = await execute_autofix(req)
            return {
                "payload": {
                    "tool": tool_name,
                    "fix": label,
                    "result": result,
                },
                "executed": 1 if result.get("executed") else 0,
                "failed": 0 if result.get("executed") else 1,
                "human_required": 0,
            }
        except Exception as exc:
            return {
                "payload": {
                    "tool": tool_name,
                    "fix": label,
                    "error": str(exc),
                },
                "executed": 0,
                "failed": 1,
                "human_required": 0,
            }

    if action in _HUMAN_FIX_ACTIONS:
        ticket = _create_human_action_ticket(tool_name, action, fix.get("command", ""))
        return {
            "payload": {
                "tool": tool_name,
                "fix": label,
                "ticket_created": ticket.id if ticket else None,
            },
            "executed": 0,
            "failed": 0,
            "human_required": 1,
        }

    return {
        "payload": {
            "tool": tool_name,
            "fix": label,
            "skipped": True,
        },
        "executed": 0,
        "failed": 0,
        "human_required": 0,
    }


def _create_human_action_ticket(tool_name: str, action: str, command: str) -> Any:
    """Create a ticket for human-required actions and assign to default user."""
    from proxym.dashboard._tickets_api import _tickets
    from proxym.dashboard.tickets import Ticket, TicketPriority, TicketType

    action_labels = {
        "info": "Manual setup required",
        "config": "Configuration required",
    }

    title = f"{action_labels.get(action, 'Action required')}: {tool_name}"
    description = f"""Tool: {tool_name}
Action needed: {action}
Command/Info: {command}

This tool requires manual intervention that cannot be automated.
Please review and complete the required setup.
"""

    try:
        mgr = _tickets()
        default_user = _get_default_user()

        ticket = Ticket(
            task=title,
            description=description,
            priority=TicketPriority.HIGH,
            type=TicketType.TASK,
            tags=["autofix", "human-required", tool_name],
        )
        created = mgr.create_ticket(ticket)

        from proxym.dashboard.tickets import ToolAssignment
        mgr.assign_tool(created.id, ToolAssignment(tool="human", agent_mode="manual"))
        created = mgr.get_ticket(created.id) or created

        if default_user:
            from proxym.dashboard.tickets import TicketComment
            comment = TicketComment(
                author="system",
                content=f"Auto-assigned to default user: {default_user.get('name', 'unknown')} ({default_user.get('email', 'no email')})",
            )
            mgr.add_comment(created.id, comment)

        return created
    except Exception as exc:
        logger.error("Failed to create human action ticket", tool=tool_name, error=str(exc))
        return None


def _get_default_user() -> dict[str, Any] | None:
    """Get the default/delegated user from users store."""
    from proxym.dashboard.users import UserManager
    try:
        mgr = UserManager.get()
        return mgr.get_default_user()
    except Exception:
        return None
