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

from anacondalib import VirtInstallMachineCase
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, skipImage, test_main  # pylint: disable=import-error


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

        disk = "/dev/vda"
        tmp_mount = "/tmp/btrfs-mount-test"
        s.partition_disk(disk, [(EFI_PARTITION_DEFAULT_SIZE, "efi"), ("1GiB", "ext4"), ("", "btrfs")])
        m.execute(f"""
        mkdir -p {tmp_mount}
        mount {disk}3 {tmp_mount}
        btrfs subvolume create {tmp_mount}/root
        btrfs subvolume create {tmp_mount}/home
        btrfs subvolume create {tmp_mount}/unused
        btrfs subvolume snapshot {tmp_mount}/root {tmp_mount}/snapshot1
        umount {tmp_mount}
        rmdir {tmp_mount}
        """)

    @skipImage("btrfs support missing on fedora-eln image", "fedora-eln-boot")
    def testBtrfsSubvolumes(self):
        """
        Description:
            Test 'Mount point mapping' screen with btrfs subvolumes and snapshots

        Expected results:
            - The installer should be able to detect / handle btrfs subvolumes and snapshots
            - The review screen should show the correct mountpoints and devices
        """
        b = self.browser
        m = self.machine
        i = Installer(b, m)
        s = Storage(b, m)
        r = Review(b, m)

        disk = "/dev/vda"
        dev = "vda"

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

        s.select_mountpoint([(dev, True)])

        # btrfs snapshots should not be available
        s.check_mountpoint_row_device_available(1, "snapshot1", False)

        # verify gathered requests
        # root partition is not auto-mapped
        s.check_mountpoint_row(1, "/", "Select a device", True)
        s.select_mountpoint_row_device(1, "root")
        s.check_mountpoint_row_format_type(1, "btrfs")

        s.check_mountpoint_row(2, "/boot/efi", "Select a device", False)
        s.select_mountpoint_row_device(2, f"{dev}1")
        s.check_mountpoint_row_format_type(2, "EFI System Partition")

        s.check_mountpoint_row(3, "/boot", "Select a device", False)
        s.select_mountpoint_row_device(3, f"{dev}2")
        s.check_mountpoint_row_format_type(3, "ext4")

        s.add_mountpoint_row()
        s.select_mountpoint_row_device(4, "home")
        s.check_mountpoint_row_reformat(4, False)
        s.select_mountpoint_row_mountpoint(4, "/home")
        s.check_mountpoint_row_format_type(4, "btrfs")

        # Toggle reformat option
        s.select_mountpoint_row_reformat(3)
        s.check_mountpoint_row_reformat(3, True)

        i.reach(i.steps.REVIEW)

        # verify review screen
        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, "ext4")
        r.check_disk_row(dev, "/", "vda3", "14.5 GB", True, "btrfs subvolume")
        r.check_disk_row(dev, "/home", "vda3", "14.5 GB", False)
        r.check_disk_row_not_present(dev, "unused")

        i.reach_on_sidebar(i.steps.INSTALLATION_METHOD)

        # Checks for nested btrfs subvolume
        tmp_mount = "/tmp/btrfs-mount-test"
        m.execute(f"""
        mkdir -p {tmp_mount}
        mount {disk}3 {tmp_mount}
        btrfs subvolume create {tmp_mount}/home/Movies
        btrfs subvolume create {tmp_mount}/home/Movies/Good_Movies
        btrfs subvolume create {tmp_mount}/home/Movies/Bad_Movies
        umount {tmp_mount}
        rmdir {tmp_mount}
        """)
        s.rescan_disks()
        s.select_mountpoint([(dev, True)])

        s.check_mountpoint_row(1, "/", "root", True)
        s.check_mountpoint_row(2, "/boot/efi", f"{dev}1", False)
        s.check_mountpoint_row(3, "/boot", f"{dev}2", False)
        s.check_mountpoint_row(4, "/home", "home", False)
        s.add_mountpoint_row()
        s.select_mountpoint_row_device(5, "home/Movies")
        s.select_mountpoint_row_mountpoint(5, "/home/Movies")
        s.add_mountpoint_row()
        s.select_mountpoint_row_device(6, "home/Movies/Good_Movies")
        s.select_mountpoint_row_mountpoint(6, "/home/Movies/Good_Movies")
        s.add_mountpoint_row()
        s.select_mountpoint_row_device(7, "home/Movies/Bad_Movies")
        s.select_mountpoint_row_mountpoint(7, "/home/Movies/Bad_Movies")

        # No error when no devices are reformatted
        for row in range(4, 7):
            s.wait_mountpoint_table_column_helper(row, "format", present=False)

        # When parent is re-formatted all child devices must be reformatted
        s.select_mountpoint_row_device(5, "home/Movies")
        s.select_mountpoint_row_reformat(5)
        s.wait_mountpoint_table_column_helper(5, "format", text="Mismatch")
        s.select_mountpoint_row_reformat(6)
        s.select_mountpoint_row_reformat(7)
        s.wait_mountpoint_table_column_helper(5, "format", present=False)

        # Check also that the rules apply to children deeper in the device tree
        s.select_mountpoint_row_reformat(4)
        s.wait_mountpoint_table_column_helper(4, "format", present=False)
        s.select_mountpoint_row_reformat(7, False)
        s.wait_mountpoint_table_column_helper(4, "format", text="Mismatch")

        # When parent is re-formmated all child devices should be
        # * either also reformatted if selected
        # * either not selected (not part of the mountpoint assignment table)
        s.remove_mountpoint_row(6, 7)
        s.remove_mountpoint_row(6, 6)
        s.wait_mountpoint_table_column_helper(4, "format", present=False)
        s.wait_mountpoint_table_column_helper(5, "format", present=False)

        i.check_next_disabled(False)

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

        disk = "/dev/vda"
        tmp_mount = "/tmp/btrfs-mount-test"
        s.partition_disk(disk, [(EFI_PARTITION_DEFAULT_SIZE, "efi"), ("1GiB", "ext4"), ("", "btrfs")])
        s.create_luks_partition(f"{disk}3", "einszweidrei", "encrypted-vol", "btrfs", close_luks=False)
        m.execute(f"""
        mkdir -p {tmp_mount}
        mount /dev/mapper/encrypted-vol {tmp_mount}
        btrfs subvolume create {tmp_mount}/root
        btrfs subvolume create {tmp_mount}/home
        btrfs subvolume create {tmp_mount}/unused
        umount {tmp_mount}
        rmdir {tmp_mount}
        """)

    def testEncryptedUnlockBTRFSonLUKS(self):
        """
        Description:
            Test that the installer can handle BTRFS on LUKS encrypted devices

        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 shows the correct mountpoints and devices
        """
        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)

        # Unlock the LUKS device
        s.unlock_all_encrypted()
        s.unlock_device("einszweidrei", ["vda3"], ["vda3"])

        s.select_mountpoint([(dev, True)])

        # Select the mountpoints
        s.select_mountpoint_row_device(1, "root")
        s.select_mountpoint_row_device(2, f"{dev}1")
        s.select_mountpoint_row_device(3, f"{dev}2")

        # Verify the review page
        i.reach(i.steps.REVIEW)
        r.check_disk_row(dev, "/boot/efi", "vda1", EFI_PARTITION_DEFAULT_SIZE_MB, False)
        r.check_disk_row(dev, "/boot", "vda2", "1.07 GB", False)
        r.check_disk_row(dev, "/", "vda3", "14.5 GB", True, "btrfs subvolume", True)


if __name__ == '__main__':
    test_main()
