"""Base classes and helper functions for boot configuration."""

import pathlib
import subprocess
import tempfile
from abc import ABC, abstractmethod

from ..builder import Logger
from ..apt_state import AptStateManager


def default_kernel_params(project: str) -> str:
    if project == "ubuntukylin":
        return (
            "file=/cdrom/preseed/ubuntu.seed locale=zh_CN "
            "keyboard-configuration/layoutcode?=cn quiet splash --- "
        )
    if project == "ubuntu-server":
        return " --- "
    else:
        return " --- quiet splash"


class BaseBootConfigurator(ABC):
    """Abstract base class for architecture-specific boot configurators.

    Subclasses must implement:
    - extract_files(): Download and extract bootloader packages
    - mkisofs_opts(): Return mkisofs command-line options
    """

    def __init__(
        self,
        logger: Logger,
        apt_state: AptStateManager,
        workdir: pathlib.Path,
        iso_root: pathlib.Path,
    ) -> None:
        self.logger = logger
        self.apt_state = apt_state
        self.scratch = workdir.joinpath("boot-stuff")
        self.iso_root = iso_root

    def download_and_extract_package(
        self, pkg_name: str, target_dir: pathlib.Path
    ) -> None:
        """Download a Debian package and extract its contents to target directory."""
        self.logger.log(f"downloading and extracting {pkg_name}")
        target_dir.mkdir(exist_ok=True, parents=True)
        with tempfile.TemporaryDirectory() as tdir_str:
            tdir = pathlib.Path(tdir_str)
            self.apt_state.download_direct(pkg_name, tdir)
            [deb] = tdir.glob("*.deb")
            dpkg_proc = subprocess.Popen(
                ["dpkg-deb", "--fsys-tarfile", deb], stdout=subprocess.PIPE
            )
            tar_proc = subprocess.Popen(
                ["tar", "xf", "-", "-C", target_dir], stdin=dpkg_proc.stdout
            )
            assert dpkg_proc.stdout is not None
            dpkg_proc.stdout.close()
            tar_proc.communicate()

    @abstractmethod
    def extract_files(self) -> None:
        """Download and extract bootloader packages to the boot tree.

        Each architecture must implement this to set up its specific bootloader files.
        """
        ...

    @abstractmethod
    def mkisofs_opts(self) -> list[str | pathlib.Path]:
        """Return mkisofs command-line options for this architecture.

        Returns:
            List of command-line options to pass to mkisofs/xorriso.
        """
        ...

    def post_process_iso(self, iso_path: pathlib.Path) -> None:
        """Post-process the ISO image after xorriso creates it."""

    def make_bootable(
        self,
        project: str,
        capproject: str,
        subarch: str,
        hwe: bool,
        dtb_dir: pathlib.Path | None = None,
    ) -> None:
        """Make the ISO bootable by extracting bootloader files."""
        self.project = project
        self.humanproject = capproject.replace("-", " ")
        self.subarch = subarch
        self.hwe = hwe
        self.dtb_dir = dtb_dir
        self.scratch.mkdir(exist_ok=True)
        with self.logger.logged("configuring boot"):
            self.extract_files()
