from debputy.plugin.api import DebputyPluginInitializer
from debputy.plugin.debputy.metadata_detectors import (
    detect_systemd_tmpfiles,
    detect_kernel_modules,
    detect_icons,
    detect_gsettings_dependencies,
    detect_xfonts,
    detect_initramfs_hooks,
    detect_systemd_sysusers,
    detect_pycompile_files,
)
from debputy.plugin.debputy.paths import (
    SYSTEMD_TMPFILES_DIR,
    INITRAMFS_HOOK_DIR,
    GSETTINGS_SCHEMA_DIR,
    SYSTEMD_SYSUSERS_DIR,
)
from debputy.plugin.debputy.shlib_metadata_detectors import detect_shlibdeps


def initialize_debputy_features(api: DebputyPluginInitializer) -> None:
    register_packager_provided_files(api)
    register_package_metadata_detectors(api)


def register_package_metadata_detectors(api: DebputyPluginInitializer) -> None:
    api.metadata_or_maintscript_detector("systemd-tmpfiles", detect_systemd_tmpfiles)
    api.metadata_or_maintscript_detector("systemd-sysusers", detect_systemd_sysusers)
    api.metadata_or_maintscript_detector("kernel-modules", detect_kernel_modules)
    api.metadata_or_maintscript_detector("icon-cache", detect_icons)
    api.metadata_or_maintscript_detector(
        "gsettings-dependencies", detect_gsettings_dependencies
    )
    api.metadata_or_maintscript_detector("xfonts", detect_xfonts)
    api.metadata_or_maintscript_detector("initramfs-hooks", detect_initramfs_hooks)
    api.metadata_or_maintscript_detector(
        "dpkg-shlibdeps", detect_shlibdeps, package_type={"deb", "udeb"}
    )
    api.metadata_or_maintscript_detector("pycompile-files", detect_pycompile_files)


def register_packager_provided_files(api: DebputyPluginInitializer) -> None:
    api.packager_provided_file(
        "tmpfiles", SYSTEMD_TMPFILES_DIR, filename_format="{name}.conf"
    )
    api.packager_provided_file(
        "sysusers", SYSTEMD_SYSUSERS_DIR, filename_format="{name}.conf"
    )
    api.packager_provided_file(
        "bug-script",
        "./usr/share/bug/{{PACKAGE}}",
        default_mode=0o0755,
        allow_name_segment=False,
        filename_format="script",
    )
    api.packager_provided_file(
        "bug-control",
        "./usr/share/bug/{{PACKAGE}}",
        allow_name_segment=False,
        filename_format="control",
    )

    api.packager_provided_file(
        "bug-presubj",
        "./usr/share/bug/{{PACKAGE}}",
        allow_name_segment=False,
        filename_format="presubj",
    )

    api.packager_provided_file("pam", "./usr/lib/pam.d")
    api.packager_provided_file("ppp.ip-up", "./etc/ppp/ip-up.d", default_mode=0o0755)
    api.packager_provided_file(
        "ppp.ip-down", "./etc/ppp/ip-down.d", default_mode=0o0755
    )
    api.packager_provided_file(
        "lintian-overrides",
        "./usr/share/lintian/overrides",
        allow_name_segment=False,
    )
    api.packager_provided_file("logrotate", "./etc/logrotate.d")
    api.packager_provided_file(
        "logcheck.cracking",
        "./etc/logcheck/cracking.d",
        post_formatting_rewrite=_replace_dot_with_underscore,
    )
    api.packager_provided_file(
        "logcheck.violations",
        "./etc/logcheck/violations.d",
        post_formatting_rewrite=_replace_dot_with_underscore,
    )
    api.packager_provided_file(
        "logcheck.violations.ignore",
        "./etc/logcheck/violations.ignore.d",
        post_formatting_rewrite=_replace_dot_with_underscore,
    )
    api.packager_provided_file(
        "logcheck.ignore.workstation",
        "./etc/logcheck/ignore.d.workstation",
        post_formatting_rewrite=_replace_dot_with_underscore,
    )
    api.packager_provided_file(
        "logcheck.ignore.server",
        "./etc/logcheck/ignore.d.server",
        post_formatting_rewrite=_replace_dot_with_underscore,
    )
    api.packager_provided_file(
        "logcheck.ignore.paranoid",
        "./etc/logcheck/ignore.d.paranoid",
        post_formatting_rewrite=_replace_dot_with_underscore,
    )

    api.packager_provided_file("mime", "./usr/lib/mime/packages/")
    api.packager_provided_file(
        "sharedmimeinfo", "./usr/share/mime/packages", filename_format="{name}.xml"
    )

    api.packager_provided_file(
        "if-pre-up", "./etc/network/if-pre-up.d/", default_mode=0o0755
    )
    api.packager_provided_file("if-up", "./etc/network/if-up.d/", default_mode=0o0755)
    api.packager_provided_file(
        "if-down", "./etc/network/if-down.d/", default_mode=0o0755
    )
    api.packager_provided_file(
        "if-post-down", "./etc/network/if-post-down.d/", default_mode=0o0755
    )

    api.packager_provided_file("cron.hourly", "./etc/cron.hourly", default_mode=0o0755)
    api.packager_provided_file("cron.daily", "./etc/cron.daily", default_mode=0o0755)
    api.packager_provided_file("cron.weekly", "./etc/cron.weekly", default_mode=0o0755)
    api.packager_provided_file(
        "cron.monthly", "./etc/cron.monthly", default_mode=0o0755
    )
    api.packager_provided_file("cron.yearly", "./etc/cron.yearly", default_mode=0o0755)
    # cron.d uses 0644 unlike the others
    api.packager_provided_file("cron.d", "./etc/cron.d")

    api.packager_provided_file(
        "initramfs-hook", INITRAMFS_HOOK_DIR, default_mode=0o0755
    )

    api.packager_provided_file(
        "modprobe", "./etc/modprobe.d", filename_format="{name}.conf"
    )

    # api.packager_provided_file(
    #     "udev",
    #     "./lib/udev/rules.d",
    #     default_priority=60,
    #     filename_format="{name}.rules",
    # )

    api.packager_provided_file(
        "gsettings-override",
        GSETTINGS_SCHEMA_DIR,
        default_priority=10,
        filename_format="{priority:02}_{name}.gschema.override",
    )

    # Special-cases that will probably not be a good example for other plugins
    api.packager_provided_file(
        "changelog",
        "./usr/share/doc/{{PACKAGE}}",
        # The "changelog.Debian" gets renamed to "changelog" for native packages elsewhere.
        # Also, the changelog trimming is also done elsewhere.
        filename_format="changelog.Debian",
        allow_name_segment=False,
        packageless_is_fallback_for_all_packages=True,
    )
    api.packager_provided_file(
        "copyright",
        "./usr/share/doc/{{PACKAGE}}",
        # The "changelog.Debian" gets renamed to "changelog" for native packages elsewhere.
        # Also, the changelog trimming is also done elsewhere.
        filename_format="copyright",
        allow_name_segment=False,
        packageless_is_fallback_for_all_packages=True,
    )
    api.packager_provided_file(
        "NEWS",
        "./usr/share/doc/{{PACKAGE}}",
        filename_format="NEWS.Debian",
        allow_name_segment=False,
        packageless_is_fallback_for_all_packages=True,
    )
    api.packager_provided_file(
        "README.Debian",
        "./usr/share/doc/{{PACKAGE}}",
        filename_format="README.Debian",
        allow_name_segment=False,
    )
    api.packager_provided_file(
        "TODO",
        "./usr/share/doc/{{PACKAGE}}",
        filename_format="TODO.Debian",
        allow_name_segment=False,
    )
    api.packager_provided_file(
        "doc-base",
        "./usr/share/doc-base",
        # TODO: We end up installing the "nameless" variant as "<pkg>.<pkg>", where debhelper
        #  just called it "<pkg>". We "fixup" the name afterwards to match debhelper, which
        #  "should" just work.  However, if someone has a "<pkg>.<pkg>.doc-base" and a
        #  "<pkg>.doc-base" file, then we accidentally skip one of them. Hopefully, no one
        #  needs this and never need to fix it... :3
        filename_format="{owning_package}.{name}",
        post_formatting_rewrite=_prettify_doc_base_file,
    )
    api.packager_provided_file(
        "shlibs",
        "DEBIAN",
        allow_name_segment=False,
        filename_format="shlibs",
        reservation_only=True,
    )
    api.packager_provided_file(
        "symbols",
        "DEBIAN",
        allow_name_segment=False,
        allow_architecture_segment=True,
        filename_format="symbols",
        reservation_only=True,
    )


def _replace_dot_with_underscore(x: str) -> str:
    return x.replace(".", "_")


def _prettify_doc_base_file(n: str) -> str:
    n_len = len(n)
    if n_len & 1 and n[n_len // 2] == "." and n[: n_len // 2] == n[n_len // 2 + 1 :]:
        return n[: n_len // 2]
    return n
