from __future__ import annotations

from pathlib import Path

from app.core.command_runner import CommandRunner


def _parse_deb_control_output(output: str) -> dict[str, str]:
    metadata: dict[str, str] = {}

    for line in output.splitlines():
        key, separator, value = line.partition(":")
        if not separator:
            continue

        normalized_key = key.strip().lower()
        if normalized_key in {"package", "version", "architecture"}:
            metadata[normalized_key] = value.strip()

    return metadata


class DebInstaller:
    def __init__(self, command_runner: CommandRunner) -> None:
        self.command_runner = command_runner

    def get_deb_metadata(self, file_path: Path) -> dict[str, str]:
        result = self.command_runner.run([
            "dpkg-deb",
            "-f",
            str(file_path),
            "Package",
            "Version",
            "Architecture",
        ])
        metadata = _parse_deb_control_output(result.stdout)
        missing_fields = [
            field
            for field in ("package", "version", "architecture")
            if not metadata.get(field)
        ]

        if missing_fields:
            raise ValueError(
                "Downloaded .deb is missing metadata fields: "
                f"{', '.join(missing_fields)}"
            )

        return metadata

    def install_deb(self, file_path: Path) -> None:
        self.command_runner.run(["apt", "install", "-y", str(file_path)])

    def remove_package(self, package_name: str, purge: bool = False) -> None:
        action = "purge" if purge else "remove"
        self.command_runner.run(["apt", action, "-y", package_name])

    def get_package_version(self, package_name: str) -> str | None:
        result = self.command_runner.run(["dpkg-query", "-W", "-f=${Version}", package_name])
        version = result.stdout.strip()
        return version or None

    def check_package_installed(self, package_name: str) -> bool:
        try:
            self.get_package_version(package_name)
            return True
        except Exception:
            return False
