# Copyright 2022 Oliver Smith
# SPDX-License-Identifier: GPL-3.0-or-later
import logging
import os

import pmb.build
import pmb.chroot.apk
import pmb.config
import pmb.flasher
import pmb.helpers.file


def odin(args, flavor, folder):
    """
    Create Odin flashable tar file with kernel and initramfs
    for devices configured with the flasher method 'heimdall-isorec'
    and with boot.img for devices with 'heimdall-bootimg'
    """
    pmb.flasher.init(args)
    suffix = "rootfs_" + args.device

    # Backwards compatibility with old mkinitfs (pma#660)
    suffix_flavor = f"-{flavor}"
    pmaports_cfg = pmb.config.pmaports.read_config(args)
    if pmaports_cfg.get("supported_mkinitfs_without_flavors", False):
        suffix_flavor = ""

    # Validate method
    method = args.deviceinfo["flash_method"]
    if not method.startswith("heimdall-"):
        raise RuntimeError("An odin flashable tar is not supported"
                           f" for the flash method '{method}' specified"
                           " in the current configuration."
                           " Only 'heimdall' methods are supported.")

    # Partitions
    partition_kernel = \
        args.deviceinfo["flash_heimdall_partition_kernel"] or "KERNEL"
    partition_initfs = \
        args.deviceinfo["flash_heimdall_partition_initfs"] or "RECOVERY"

    # Temporary folder
    temp_folder = "/tmp/odin-flashable-tar"
    if os.path.exists(f"{args.work}/chroot_native{temp_folder}"):
        pmb.chroot.root(args, ["rm", "-rf", temp_folder])

    # Odin flashable tar generation script
    # (because redirecting stdin/stdout is not allowed
    # in pmbootstrap's chroot/shell functions for security reasons)
    odin_script = f"{args.work}/chroot_rootfs_{args.device}/tmp/_odin.sh"
    with open(odin_script, "w") as handle:
        odin_kernel_md5 = f"{partition_kernel}.bin.md5"
        odin_initfs_md5 = f"{partition_initfs}.bin.md5"
        odin_device_tar = f"{args.device}.tar"
        odin_device_tar_md5 = f"{args.device}.tar.md5"

        handle.write(
            "#!/bin/sh\n"
            f"cd {temp_folder}\n")
        if method == "heimdall-isorec":
            handle.write(
                # Kernel: copy and append md5
                f"cp /boot/vmlinuz{suffix_flavor} {odin_kernel_md5}\n"
                f"md5sum -t {odin_kernel_md5} >> {odin_kernel_md5}\n"
                # Initramfs: recompress with lzop, append md5
                f"gunzip -c /boot/initramfs{suffix_flavor}"
                f" | lzop > {odin_initfs_md5}\n"
                f"md5sum -t {odin_initfs_md5} >> {odin_initfs_md5}\n")
        elif method == "heimdall-bootimg":
            handle.write(
                # boot.img: copy and append md5
                f"cp /boot/boot.img{suffix_flavor} {odin_kernel_md5}\n"
                f"md5sum -t {odin_kernel_md5} >> {odin_kernel_md5}\n")
        handle.write(
            # Create tar, remove included files and append md5
            f"tar -c -f {odin_device_tar} *.bin.md5\n"
            "rm *.bin.md5\n"
            f"md5sum -t {odin_device_tar} >> {odin_device_tar}\n"
            f"mv {odin_device_tar} {odin_device_tar_md5}\n")

    commands = [["mkdir", "-p", temp_folder],
                ["cat", "/tmp/_odin.sh"],  # for the log
                ["sh", "/tmp/_odin.sh"],
                ["rm", "/tmp/_odin.sh"]
                ]
    for command in commands:
        pmb.chroot.root(args, command, suffix)

    # Move Odin flashable tar to native chroot and cleanup temp folder
    pmb.chroot.user(args, ["mkdir", "-p", "/home/pmos/rootfs"])
    pmb.chroot.root(args, ["mv", f"/mnt/rootfs_{args.device}{temp_folder}"
                           f"/{odin_device_tar_md5}", "/home/pmos/rootfs/"]),
    pmb.chroot.root(args, ["chown", "pmos:pmos",
                           f"/home/pmos/rootfs/{odin_device_tar_md5}"])
    pmb.chroot.root(args, ["rmdir", temp_folder], suffix)

    # Create the symlink
    file = f"{args.work}/chroot_native/home/pmos/rootfs/{odin_device_tar_md5}"
    link = f"{folder}/{odin_device_tar_md5}"
    pmb.helpers.file.symlink(args, file, link)

    # Display a readable message
    msg = f" * {odin_device_tar_md5}"
    if method == "heimdall-isorec":
        msg += " (Odin flashable file, contains initramfs and kernel)"
    elif method == "heimdall-bootimg":
        msg += " (Odin flashable file, contains boot.img)"
    logging.info(msg)
