"""Background install runner — executes the 15-step install loop."""

from __future__ import annotations

import asyncio
from typing import Any, Callable

from easyclaw_tui.state import InstallState, StepStatus
from easyclaw_tui.steps.base import StepResult
from easyclaw_tui.messages import InstallStepStarted, InstallStepCompleted, InstallFinished

from easyclaw_tui.steps.s01_preflight import PreflightStep
from easyclaw_tui.steps.s02_nodejs import NodejsStep
from easyclaw_tui.steps.s03_openclaw import OpenClawStep
from easyclaw_tui.steps.s04_tools import ToolsStep
from easyclaw_tui.steps.s05_config import ConfigStep
from easyclaw_tui.steps.s06_token import TokenStep
from easyclaw_tui.steps.s07_write_config import WriteConfigStep
from easyclaw_tui.steps.s08_env_vars import EnvVarsStep
from easyclaw_tui.steps.s09_workspace import WorkspaceStep
from easyclaw_tui.steps.s10_validate import ValidateStep
from easyclaw_tui.steps.s11_init_gateway import InitGatewayStep
from easyclaw_tui.steps.s12_systemd import SystemdStep
from easyclaw_tui.steps.s13_mcp import McpStep
from easyclaw_tui.steps.s14_channel import ChannelStep
from easyclaw_tui.steps.s15_health import HealthStep

STEP_CLASSES = [
    PreflightStep,
    NodejsStep,
    OpenClawStep,
    ToolsStep,
    ConfigStep,
    TokenStep,
    WriteConfigStep,
    EnvVarsStep,
    WorkspaceStep,
    ValidateStep,
    InitGatewayStep,
    SystemdStep,
    McpStep,
    ChannelStep,
    HealthStep,
]

# Global log buffer — dict[step_num] = list[(level, message)]
# Accessible by the get_install_logs tool.
install_log_buffer: dict[int, list[tuple[str, str]]] = {}


async def run_install_steps(
    state: InstallState,
    post_message: Callable,
) -> bool:
    """Run all 15 install steps, posting Textual Messages for each event.

    Args:
        state: Shared install state.
        post_message: Callable to post Textual Messages (screen.post_message).

    Returns:
        True if all steps passed/skipped, False if any failed.
    """
    global install_log_buffer
    install_log_buffer.clear()

    for i, step_cls in enumerate(STEP_CLASSES):
        step_num = i + 1
        step_info = state.steps[i]

        # Prepare per-step log buffer
        step_logs: list[tuple[str, str]] = []
        install_log_buffer[step_num] = step_logs

        def log_cb(level: str, msg: str, _logs=step_logs) -> None:
            _logs.append((level, msg))

        # Notify UI
        post_message(InstallStepStarted(step_num, step_info.name))
        state.set_step_status(step_num, StepStatus.RUNNING)

        # Create and run step (no StepPanel — use log_callback)
        step = step_cls(state, panel=None, log_callback=log_cb)
        try:
            result = await step.run()
        except Exception as e:
            log_cb("error", f"Step failed with exception: {e}")
            result = StepResult(success=False, message=str(e))

        # Update state
        if result.success:
            state.set_step_status(step_num, StepStatus.SUCCESS)
        elif result.skipped:
            state.set_step_status(step_num, StepStatus.SKIPPED)
        else:
            state.set_step_status(step_num, StepStatus.FAILED)

        # Notify UI
        post_message(InstallStepCompleted(step_num, step_info.name, result))
        state.current_step = step_num + 1

        # Stop on critical failures — later steps depend on OpenClaw binary
        if not result.success and not result.skipped and step_num <= 3:
            log_cb("error", f"Critical step {step_num} failed — stopping install")
            break

    all_passed = all(
        s.status in (StepStatus.SUCCESS, StepStatus.SKIPPED)
        for s in state.steps
    )
    post_message(InstallFinished(all_passed))
    return all_passed


def get_logs_for_step(step_num: int = 0) -> str:
    """Get install logs for a specific step or all recent.

    Args:
        step_num: Step number (1-15), or 0 for all recent logs.

    Returns:
        Formatted log string.
    """
    if step_num > 0:
        logs = install_log_buffer.get(step_num, [])
        if not logs:
            return f"No logs for step {step_num}."
        lines = [f"Step {step_num} logs:"]
        for level, msg in logs:
            icon = {"ok": "\u2713", "warn": "\u26a0", "error": "\u2717", "info": "\u2192"}.get(level, " ")
            lines.append(f"  {icon} [{level}] {msg}")
        return "\n".join(lines)

    # All logs
    if not install_log_buffer:
        return "No install logs yet."

    lines = []
    for sn in sorted(install_log_buffer.keys()):
        step_logs = install_log_buffer[sn]
        if step_logs:
            lines.append(f"\nStep {sn}:")
            for level, msg in step_logs[-5:]:  # Last 5 per step
                icon = {"ok": "\u2713", "warn": "\u26a0", "error": "\u2717", "info": "\u2192"}.get(level, " ")
                lines.append(f"  {icon} [{level}] {msg}")
    return "\n".join(lines) if lines else "No install logs yet."
