#!/usr/bin/python3
#
# Copyright (C) 2024 Red Hat, Inc.
# SPDX-License-Identifier: LGPL-2.1-or-later

from anacondalib import INSTALLER_VM_MEMORY_MB, VirtInstallMachineCase, disk_images
from installer import Installer
from review import Review
from storage import EFI_PARTITION_DEFAULT_SIZE, EFI_PARTITION_DEFAULT_SIZE_MB, Storage
from testlib import nondestructive, test_main  # pylint: disable=import-error


# TODO: these tests should be made nondestructive
class TestStorageMountPointsRAIDDestructive(VirtInstallMachineCase):
    provision = {"machine1": {"memory_mb": INSTALLER_VM_MEMORY_MB}}

    def _testEncryptedUnlockRAIDonLUKS_partition_disk(self):
        b = self.browser
        m = self.machine
        s = Storage(b, m)

        # EFI system partition, /boot partition, / on RAID
        disk = "/dev/vda"
        s.partition_disk(disk, [(EFI_PARTITION_DEFAULT_SIZE, "efi"), ("1GiB", "xfs"), ("5GiB", None), ("5GiB", None)])
        s.create_luks_partition(f"{disk}3", "einszweidrei", "encrypted-vol", close_luks=False)
        s.create_luks_partition(f"{disk}4", "einszweidrei", "encrypted-vol2", close_luks=False)
        s.create_raid_device("encryptedraid", "raid1", ["/dev/mapper/encrypted-vol", "/dev/mapper/encrypted-vol2"])
        m.execute("mkfs.xfs /dev/md/encryptedraid")

    def testEncryptedUnlockRAIDonLUKS(self):
        """
        Description:
            Test that we can use RAID on LUKS partitions with the mount point
            mapping scenario

        Expected results:
            - The 'Unlock' dialog is available for unlocking the partitions before entering the mount point mapping
            - The user can unlock the disk using a passphrase.
            - The user can select the unlocked devices in the mount point mapping
              table.
            - The review screen should show the correct mountpoints and devices
        """
        # RAID on LUKS: partition -> LUKS -> RAID -> filesystem
        b = self.browser
        m = self.machine
        i = Installer(b, m)
        s = Storage(b, m)
        r = Review(b, m)
        dev = "vda"

        i.open()
        i.reach(i.steps.INSTALLATION_METHOD)

        # select only vda and check that we don't try to unlock the LUKS partition on vdb
        s.unlock_all_encrypted()
        s.unlock_device("einszweidrei", ["vda3", "vda4"], ["vda3", "vda4"])
        b.wait_not_present(f"#{i.steps.CUSTOM_MOUNT_POINT}-table tbody tr:nth-child(4) td[data-label='Format type'] #unlock-luks-btn")

        s.select_mountpoint()

        s.select_mountpoint_row_device(1, "encryptedraid")
        s.check_mountpoint_row_format_type(1, "xfs")

        s.check_mountpoint_row_mountpoint(2, "/boot/efi")
        s.select_mountpoint_row_device(2, f"{dev}1")
        s.check_mountpoint_row_mountpoint(3, "/boot")
        s.select_mountpoint_row_device(3, f"{dev}2")
        s.select_mountpoint_row_reformat(3)
        s.check_mountpoint_row_reformat(3, True)

        i.reach(i.steps.REVIEW)

        r.check_disk(dev, "16.1 GB vda (Virtio Block Device)")

        r.check_disk_row(dev, "/boot/efi", "vda1", EFI_PARTITION_DEFAULT_SIZE_MB, False, "efi")
        r.check_disk_row(dev, "/boot", "vda2", "1.07 GB", True, "xfs")
        r.check_disk_row(dev, "/", "vda3, vda4, RAID", "5.35 GB", True, "xfs", True)

    def _testEncryptedUnlockLUKSonRAID_partition_disk(self):
        b = self.browser
        m = self.machine
        s = Storage(b, m)

        disk = "/dev/vda"

        s.partition_disk(disk, [(EFI_PARTITION_DEFAULT_SIZE, "efi"), ("1GiB", "xfs"), ("5GiB", None), ("5GiB", None)])
        s.create_raid_device("encryptedraid", "raid1", [f"{disk}3", f"{disk}4"])
        s.create_luks_partition("/dev/md/encryptedraid", "einszweidrei", "encrypted-vol", "xfs")

    def testEncryptedUnlockLUKSonRAID(self):
        """
        Description:
            Test 'Mount Point Mapping' with LUKS on RAID partitions

        Expected results:
            - The 'Unlock' dialog is displayed before entering the mount point mapping
              screen.
            - The user can unlock the disk using a passphrase.
            - The user can select the unlocked devices in the mount point mapping
              table.
            - The review screen should show the correct mountpoints and devices
        """
        # LUKS on RAID: partition -> RAID -> LUKS -> filesystem
        b = self.browser
        m = self.machine
        i = Installer(b, m)
        s = Storage(b, m)
        r = Review(b, m)

        # EFI system partition, /boot partition, / on RAID
        dev = "vda"

        i.open()
        i.reach(i.steps.INSTALLATION_METHOD)

        # select only vda and check that we don't try to unlock the LUKS partition on vdb
        s.unlock_all_encrypted()
        s.unlock_device("einszweidrei", ["encryptedraid"], ["encryptedraid"])

        s.select_mountpoint()

        s.check_mountpoint_row_mountpoint(2, "/boot/efi")
        s.select_mountpoint_row_device(2, f"{dev}1")
        s.check_mountpoint_row_mountpoint(3, "/boot")
        s.select_mountpoint_row_device(3, f"{dev}2")
        s.select_mountpoint_row_reformat(1)
        s.check_mountpoint_row_reformat(1, True)

        toggle_selector = f"#{i.steps.CUSTOM_MOUNT_POINT}-table-row-1-device-select-toggle:not([disabled]):not([aria-disabled=true])"
        b.click(toggle_selector)
        b.click(".pf-v6-c-menu__content li:nth-of-type(3) button")
        b.wait_not_present(".pf-v6-c-menu")
        b.wait_js_func("ph_text", f"#{i.steps.CUSTOM_MOUNT_POINT}-table-row-1 .pf-v6-c-select__toggle-text", "luks")

        s.check_mountpoint_row_format_type(1, "xfs")

        i.reach(i.steps.REVIEW)
        r.check_disk(dev, "16.1 GB vda (Virtio Block Device)")
        r.check_disk_row(dev, "/boot/efi", "vda1", EFI_PARTITION_DEFAULT_SIZE_MB, False, "efi")
        r.check_disk_row(dev, "/boot", "vda2", "1.07 GB", False, "xfs")
        r.check_disk_row(dev, "/", "vda3, vda4, RAID", "5.35 GB", True, "xfs", True)


@nondestructive
class TestStorageMountPointsRAID(VirtInstallMachineCase):
    def _testRAID0Scenario_0_partition_disk(self):
        b = self.browser
        m = self.machine
        s = Storage(b, m)

        # EFI system partition, /boot partition, / on RAID
        s.partition_disk("/dev/vda", [(EFI_PARTITION_DEFAULT_SIZE, "efi"), ("1GB", "xfs")])
        self.addCleanup(
            lambda: m.execute(
            """
            mdadm --stop /dev/md/SOMERAID || true
            mdadm --remove /dev/md/SOMERAID || true
            """, timeout=90)
        )
        s.create_raid_device("SOMERAID", "raid0", ["/dev/vdb", "/dev/vdc"])
        # Create GPT table and / ext4 partition on the RAID device
        m.execute(
        """
        sgdisk --zap-all /dev/md/SOMERAID
        sgdisk --new=0:0:0 --typecode=0:8300 --change-name=0:'/' /dev/md/SOMERAID
        udevadm settle
        mkfs.ext4 -F /dev/md/SOMERAID1
        """, timeout=90)

    @disk_images([("", 15), ("", 15), ("", 15)])
    def testRAID0Scenario_0(self):
        """
        Test scenario with three disks:

        - ESP and '/boot' are on 'vda'.
        - A RAID 0 array is created using 'vdb' and 'vdc'.
        - The root filesystem ('/') is placed on the RAID 0 device.
        """
        b = self.browser
        m = self.machine
        i = Installer(b, m)
        s = Storage(b, m)
        r = Review(b, m)

        i.open()
        i.reach(i.steps.INSTALLATION_METHOD)

        s.select_mountpoint([("vda", True), ("MDRAID-SOMERAID", True)]) # Select both disks

        s.check_mountpoint_row_mountpoint(2, "/boot/efi")
        s.select_mountpoint_row_device(2, "vda1")
        s.select_mountpoint_row_reformat(2, False)

        s.check_mountpoint_row_mountpoint(3, "/boot")
        s.select_mountpoint_row_device(3, "vda2")
        s.select_mountpoint_row_reformat(3, False)

        s.check_mountpoint_row_mountpoint(1, "/")
        s.select_mountpoint_row_device(1, "SOMERAID1")
        s.select_mountpoint_row_reformat(1, False)

        i.next(should_fail=True)
        i.reach(i.steps.REVIEW)

        r.check_disk("vda", "16.1 GB vda (Virtio Block Device)")
        r.check_disk_row("vda", "/boot/efi", "vda1", EFI_PARTITION_DEFAULT_SIZE_MB, False)
        r.check_disk_row("vda", "/boot", "vda2", "1.00 GB", False)
        r.check_disk("MDRAID-SOMERAID", "32.2 GB MDRAID-SOMERAID (MDRAID set (stripe))")
        r.check_disk_row("MDRAID-SOMERAID", "/", "SOMERAID1, RAID", "32.2 GB", False)


if __name__ == '__main__':
    test_main()
