"""Base class for install steps."""

from __future__ import annotations

import asyncio
import subprocess
from dataclasses import dataclass, field
from typing import TYPE_CHECKING

if TYPE_CHECKING:
    from easyclaw_tui.state import InstallState
    from easyclaw_tui.widgets.step_panel import StepPanel


@dataclass
class StepResult:
    success: bool = True
    skipped: bool = False
    message: str = ""


class BaseStep:
    """Base class for an install step."""

    STEP_NUM: int = 0
    STEP_NAME: str = ""

    def __init__(self, state: InstallState, panel: StepPanel) -> None:
        self.state = state
        self.panel = panel

    async def run(self) -> StepResult:
        """Override in subclasses. Execute the step logic."""
        raise NotImplementedError

    # ─── Helpers ──────────────────────────────────────────

    async def run_cmd(self, cmd: str, check: bool = True) -> tuple[int, str, str]:
        """Run a shell command asynchronously. Returns (returncode, stdout, stderr)."""
        proc = await asyncio.create_subprocess_shell(
            cmd,
            stdout=asyncio.subprocess.PIPE,
            stderr=asyncio.subprocess.PIPE,
        )
        stdout, stderr = await proc.communicate()
        out = stdout.decode(errors="replace").strip()
        err = stderr.decode(errors="replace").strip()
        return proc.returncode, out, err

    async def cmd_ok(self, cmd: str) -> bool:
        """Return True if command exits 0."""
        rc, _, _ = await self.run_cmd(cmd, check=False)
        return rc == 0

    async def cmd_output(self, cmd: str) -> str:
        """Return stdout of a command, or empty string on failure."""
        rc, out, _ = await self.run_cmd(cmd, check=False)
        return out if rc == 0 else ""

    def sudo(self, cmd: str) -> str:
        """Prefix with sudo if needed."""
        if self.state.use_sudo:
            return f"sudo {cmd}"
        return cmd

    def ok(self, msg: str) -> None:
        self.panel.log_ok(msg)

    def warn(self, msg: str) -> None:
        self.panel.log_warn(msg)

    def error(self, msg: str) -> None:
        self.panel.log_error(msg)

    def info(self, msg: str) -> None:
        self.panel.log_info(msg)
