import textwrap
from typing import cast, Any, TYPE_CHECKING

from debputy.plugin.api import (
    DebputyPluginInitializer,
    VirtualPath,
    BinaryCtrlAccessor,
    PackageProcessingContext,
)

from debputy.util import POSTINST_DEFAULT_CONDITION

if TYPE_CHECKING:
    from debputy.filesystem_scan import VirtualPathBase
    from debputy.plugin.api.impl import DebputyPluginInitializerProvider

PRIVATE_PYTHON_DIR = "/usr/share/debputy"


def _maintscript_generator(
    _path: VirtualPath,
    ctrl: BinaryCtrlAccessor,
    context: PackageProcessingContext,
) -> None:
    maintscript = ctrl.maintscript
    package_name = context.binary_package.name

    # When `debputy` becomes a stand-alone package, it should have these maintscripts instead of dh-debputy
    # Admittedly, I hope to get rid of this plugin before then, but ...
    assert package_name == "dh-debputy", "Update the self-hosting plugin"

    ctrl.dpkg_trigger("interest-noawait", PRIVATE_PYTHON_DIR)
    maintscript.unconditionally_in_script(
        "postinst",
        textwrap.dedent(
            f"""\
        if {POSTINST_DEFAULT_CONDITION} || [ "$1" = "triggered" ] ; then
            # Ensure all plugins are byte-compiled (plus uninstalled plugins are cleaned up)
            py3clean {PRIVATE_PYTHON_DIR}
            if command -v py3compile >/dev/null 2>&1; then
                py3compile {PRIVATE_PYTHON_DIR}
            fi
            if command -v pypy3compile >/dev/null 2>&1; then
                pypy3compile {PRIVATE_PYTHON_DIR} || true
            fi
        fi
    """
        ),
    )
    maintscript.unconditionally_in_script(
        "prerm",
        textwrap.dedent(
            f"""\
    if command -v py3clean >/dev/null 2>&1; then
        py3clean {PRIVATE_PYTHON_DIR}
    else
        find {PRIVATE_PYTHON_DIR}/ -type d -name __pycache__ -empty -print0 | xargs --null --no-run-if-empty rmdir
    fi
    """
        ),
    )


def _rtupdate_generator(
    fs_root: VirtualPath,
    _: Any,
    context: "PackageProcessingContext",
) -> None:
    package_name = context.binary_package.name
    # When `debputy` becomes a stand-alone package, it should have these scripts instead of dh-debputy
    # Admittedly, I hope to get rid of this plugin before then, but ...
    assert package_name == "dh-debputy", "Update the self-hosting plugin"
    rtupdate_dir: VirtualPathBase = cast(
        "VirtualPathBase",
        fs_root.mkdirs("/usr/share/python3/runtime.d/"),
    )
    with rtupdate_dir.open_child("debputy.rtupdate", "w") as fd:
        template = textwrap.dedent(
            f"""\
        #! /bin/sh
        if [ "$1" = rtupdate ]; then
            py3clean {PRIVATE_PYTHON_DIR}
            py3compile {PRIVATE_PYTHON_DIR}
        fi
        """
        )
        fd.write(template)
    rtupdate_dir["debputy.rtupdate"].chmod(0o755)


def initializer(api: DebputyPluginInitializer) -> None:
    api.metadata_or_maintscript_detector(
        "debputy-self-hosting",
        _maintscript_generator,
    )
    internal_api: DebputyPluginInitializerProvider = cast(
        "DebputyPluginInitializerProvider", api
    )
    internal_api.package_processor(
        "rtupdate",
        _rtupdate_generator,
    )
