"""Setup sequence execution for the dynamic installer.

This module extracted the logic from `src/armorer/installers/dynamic.py` to
reduce monolith size while preserving behavior.
"""

from __future__ import annotations

import os
import sys
import shutil
from pathlib import Path
from typing import Any, Callable, Dict, List

import typer
from rich.panel import Panel


def execute_setup_sequence_impl(
    installer: Any,
    steps: List[Dict[str, Any]],
    *,
    show_banner: bool,
    context: str,
    console: Any,
    step_start: Callable[[str], Any],
    step_done: Callable[[str, str], None],
    step_fail: Callable[[str, str], None],
    looks_like_host_disk_full: Callable[[str], bool],
    render_host_disk_full_panel: Callable[[str, str], None],
    looks_like_docker_storage_io_error: Callable[[str], bool],
    render_docker_storage_fault_panel: Callable[[str, str], None],
) -> None:
    # `context` is kept for forward-compat; current monolith behavior doesn't use it.
    _ = context

    if show_banner:
        console.print()
        console.print(
            Panel(
                "[bold yellow]🔧 Pre-Deployment Setup[/bold yellow]\n"
                "Armorer detected setup steps that should run before deployment.",
                border_style="yellow",
                expand=True,
            )
        )

    for step in steps:
        step_type = step.get("type")
        step_label = step.get("label", "Unknown step")

        if step_type == "env_copy":
            # Auto-execute: copy .env.default → .env
            src, dst = step["source"], step["target"]
            label = f"Copying {Path(src).name} → .env"
            with step_start(label):
                shutil.copy2(src, dst)
            try:
                detail = str(
                    Path(dst).parent.relative_to(installer._host_visible_path(installer.install_dir))
                )
            except Exception:
                detail = str(Path(dst).parent)
            step_done(label, detail)

        elif step_type == "makefile":
            # Show but ask before running (could be heavyweight)
            console.print(f"  [dim]Found: {step_label}[/dim]")

        elif step_type == "script":
            console.print(f"  [dim]Found: {step_label}[/dim]")

        elif step_type == "command":
            cmd = step.get("command", "")
            raw_cwd = Path(step.get("cwd", str(installer.install_dir)))
            cwd = raw_cwd if raw_cwd.is_absolute() else Path(installer.install_dir) / raw_cwd
            required = bool(step.get("required", True))
            if cmd:
                effective_env = os.environ.copy()
                effective_env.update({
                    "ARMORER_PYTHON": sys.executable,
                    "ARMORER_REPO_ROOT": str(Path(__file__).resolve().parents[3]),
                })
                res = installer._run_with_live_logs(
                    cmd,
                    cwd=cwd,
                    shell=True,
                    label=step_label,
                    env=effective_env,
                    check=False,
                )
                if res.returncode == 0:
                    step_done(step_label)
                else:
                    fallback_image = installer._docker_build_target_image(cmd, shell=True)
                    if fallback_image and installer._docker_image_exists(fallback_image):
                        step_done(step_label, f"reusing existing image {fallback_image}")
                        continue
                    if looks_like_host_disk_full(res.stdout or ""):
                        render_host_disk_full_panel(step_label, res.stdout or "")
                    if looks_like_docker_storage_io_error(res.stdout or ""):
                        render_docker_storage_fault_panel(step_label, res.stdout or "")
                    step_fail(step_label, "failed")
                    if required:
                        detail = (res.stdout or "").strip()
                        raise typer.Exit(
                            f"Required setup step failed: {step_label}"
                            + (f"\n{detail[-1200:]}" if detail else "")
                        )

    console.print()
