# Copyright 2023 Oliver Smith
# SPDX-License-Identifier: GPL-3.0-or-later
from getpass import getpass

import pmb.chroot.other
import pmb.config
import pmb.install
import pmb.parse
from pmb.core import Chroot, ChrootType
from pmb.core.arch import Arch
from pmb.core.context import get_context
from pmb.helpers import logging
from pmb.helpers.exceptions import NonBugError
from pmb.types import PmbArgs


def _parse_flavor(device: str, autoinstall: bool = True) -> str:
    """
    Verify the flavor argument if specified, or return a default value.

    :param autoinstall: make sure that at least one kernel flavor is installed
    """
    # Install a kernel and get its "flavor", where flavor is a pmOS-specific
    # identifier that is typically in the form
    # "postmarketos-<manufacturer>-<device/chip>", e.g.
    # "postmarketos-qcom-sdm845"
    chroot = Chroot(ChrootType.ROOTFS, device)
    flavor = pmb.chroot.other.kernel_flavor_installed(chroot, autoinstall)

    if not flavor:
        raise RuntimeError(
            f"No kernel flavors installed in chroot '{chroot}'! Please let"
            " your device package depend on a package starting with 'linux-'."
        )
    return flavor


def _parse_suffix(args: PmbArgs) -> Chroot:
    deviceinfo = pmb.parse.deviceinfo()
    if getattr(args, "image", None):
        rootfs = Chroot.native() / f"home/pmos/rootfs/{deviceinfo.codename}.img"
        return Chroot(ChrootType.IMAGE, str(rootfs))
    if getattr(args, "rootfs", None):
        return Chroot(ChrootType.ROOTFS, get_context().config.device)
    elif args.buildroot:
        if args.buildroot == "device":
            return Chroot.buildroot(deviceinfo.arch)
        else:
            return Chroot.buildroot(Arch.from_str(args.buildroot))
    elif args.suffix:
        (t_, s) = args.suffix.split("_")
        t: ChrootType = ChrootType(t_)
        return Chroot(t, s)
    else:
        return Chroot(ChrootType.NATIVE)


def install(args: PmbArgs) -> None:
    config = get_context().config
    device = config.device
    deviceinfo = pmb.parse.deviceinfo(device)
    is_split = args.split if args.split is not None else False
    if args.no_fde:
        logging.warning("WARNING: --no-fde is deprecated, as it is now the default.")
    if args.rsync and args.full_disk_encryption:
        raise ValueError("Installation using rsync is not compatible with full disk encryption.")
    if args.rsync and not args.disk:
        raise ValueError("Installation using rsync only works with --disk.")

    if args.rsync and args.filesystem == "btrfs":
        raise ValueError("Installation using rsync is not currently supported on btrfs filesystem.")

    if not args.disk and args.split is None:
        # Default to split if the flash method requires it
        flasher = pmb.config.flashers.get(deviceinfo.flash_method, {})
        if flasher.get("split", False):
            is_split = True

    # Android recovery zip related
    if args.android_recovery_zip and args.filesystem:
        raise ValueError(
            "--android-recovery-zip cannot be combined with --filesystem (patches welcome)"
        )
    if args.android_recovery_zip and args.full_disk_encryption:
        logging.info(
            "WARNING: --fde is rarely used in combination with"
            " --android-recovery-zip. If this does not work, consider"
            " using another method (e.g. installing via netcat)"
        )
        logging.info(
            "WARNING: the kernel of the recovery system (e.g. TWRP)"
            f" must support the cryptsetup cipher '{args.cipher}'."
        )
        logging.info(
            "If you know what you are doing, consider setting a"
            " different cipher with 'pmbootstrap install --cipher=..."
            " --fde --android-recovery-zip'."
        )

    # Don't install locally compiled packages and package signing keys
    if not args.install_local_pkgs:
        # Implies that we don't build outdated packages (overriding the answer
        # in 'pmbootstrap init')
        config.build_pkgs_on_install = False

        # Safest way to avoid installing local packages is having none
        if list((config.work / "packages").glob("*")):
            raise ValueError(
                "--no-local-pkgs specified, but locally built"
                " packages found. Consider 'pmbootstrap zap -p'"
                " to delete them."
            )

    if not args.password:
        args.password = getpass(f"Choose a password for the user '{config.user}': ")
        if getpass(f"Confirm password for '{config.user}': ") != args.password:
            raise NonBugError("Passwords did not match!")

    # Verify that the root filesystem is supported by current pmaports branch
    pmb.install.get_root_filesystem(args.filesystem)

    pmb.install.install(args, is_split)
