from __future__ import annotations

from dataclasses import dataclass
from pathlib import Path
import subprocess

from .device import FlasherError


@dataclass(frozen=True)
class FlashromConfig:
    programmer: str
    flashrom_bin: str = "flashrom"
    chip: str | None = None

    def base_command(self) -> list[str]:
        command = [self.flashrom_bin, "-p", self.programmer]
        if self.chip:
            command.extend(["-c", self.chip])
        return command


def default_backup_path(firmware_path: str | Path) -> Path:
    path = Path(firmware_path)
    suffix = path.suffix or ".bin"
    return path.with_name(f"{path.stem}.backup{suffix}")


def read_flash(
    output_path: str | Path,
    *,
    config: FlashromConfig,
) -> None:
    _run_flashrom(config.base_command() + ["-r", str(output_path)])


def write_flash(
    firmware_path: str | Path,
    *,
    config: FlashromConfig,
    verify: bool = True,
) -> None:
    command = config.base_command()
    if not verify:
        command.append("-n")
    command.extend(["-w", str(firmware_path)])
    _run_flashrom(command)


def _run_flashrom(command: list[str]) -> None:
    try:
        subprocess.run(command, check=True)
    except FileNotFoundError as exc:
        raise FlasherError(
            f"flashrom executable '{command[0]}' was not found; install flashrom or pass --flashrom-bin"
        ) from exc
    except subprocess.CalledProcessError as exc:
        rendered = " ".join(command)
        raise FlasherError(f"flashrom failed with exit code {exc.returncode}: {rendered}") from exc
