#
#   Debian Changes Bot
#   Copyright (C) 2016-2026 Sebastian Ramacher <sramacher@debian.org>
#
#   This program is free software: you can redistribute it and/or modify
#   it under the terms of the GNU Affero General Public License as
#   published by the Free Software Foundation, either version 3 of the
#   License, or (at your option) any later version.
#
#   This program is distributed in the hope that it will be useful,
#   but WITHOUT ANY WARRANTY; without even the implied warranty of
#   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#   GNU Affero General Public License for more details.
#
#   You should have received a copy of the GNU Affero General Public License
#   along with this program.  If not, see <http://www.gnu.org/licenses/>.

import apt_pkg
from pathlib import Path

from . import DataSource
from ..utils.decoding import split_address


class AptArchive(DataSource):
    @staticmethod
    def interval() -> int:
        # re-open cache every 30 min
        return 30 * 60

    @staticmethod
    def name() -> str:
        return "APT archive"

    def __init__(self, config_dir: Path, state_dir: Path) -> None:
        super().__init__()

        config = apt_pkg.config
        config["Dir::Etc"] = str(config_dir.resolve())
        config["Dir::State"] = str((state_dir / "state").resolve())
        config["Dir::Cache"] = str((state_dir / "cache").resolve())
        apt_pkg.init_config()
        apt_pkg.init_system()

        Path(apt_pkg.config.find_dir("Dir::State::Lists")).mkdir(
            parents=True, exist_ok=True
        )
        Path(config["Dir::Cache"]).mkdir(parents=True, exist_ok=True)

        self.cache = apt_pkg.Cache(None)
        self.depcache = apt_pkg.DepCache(self.cache)
        self.source_list = apt_pkg.SourceList()
        self.source_list.read_main_list()

    def update_index(self, ignore_errors: bool = False) -> None:
        import apt.progress.base

        lists_lock = Path(apt_pkg.config.find_dir("Dir::State::Lists")) / "lock"
        with apt_pkg.FileLock(str(lists_lock)):
            try:
                self.cache.update(apt.progress.base.AcquireProgress(), self.source_list)
            except apt_pkg.Error as e:
                if not ignore_errors:
                    raise DataSource.DataError(f"Failed to update cache: {e}")

    def update(self) -> None:
        self.cache = apt_pkg.Cache(None)
        self.depcache = apt_pkg.DepCache(self.cache)

    def get_maintainer(self, package: str) -> dict[str, str]:
        from .. import pseudo_packages

        maintainer = pseudo_packages.get_maintainer(package)
        if maintainer is not None:
            return split_address(maintainer)

        if package in self.cache:
            candidate = self.depcache.get_candidate_ver(self.cache[package])
            if candidate is not None:
                records = apt_pkg.PackageRecords(self.cache)
                if records.lookup(candidate.file_list[0]):
                    return split_address(records.maintainer)

                # delete record iterator
                del records

        if package.startswith("src:"):
            package = package[4:]

        records = apt_pkg.SourceRecords()
        if records.lookup(package):
            version = records.version
            maintainer = records.maintainer
            while records.lookup(package) is not None:
                if apt_pkg.version_compare(records.version, version) > 0:
                    version = records.version
                    maintainer = records.maintainer

            return split_address(maintainer)

        raise DataSource.DataError(f"Unable to get maintainer for {package}.")
