# SPDX-License-Identifier: GPL-3.0-or-later
"""
Tests for checking built image with VirtualBox.
"""

import os
import pathlib
import random
import string
import subprocess
import tempfile
import time

import pytest


@pytest.fixture(name='random_string')
def fixture_random_string():
    """Generate a random string."""

    def _random_string():
        return ''.join(
            [random.choice(string.ascii_lowercase) for _ in range(8)])

    return _random_string


@pytest.fixture(name='build_info')
def fixture_build_info(random_string):
    """Create basic build information."""
    with tempfile.TemporaryDirectory() as output_dir:
        yield {
            'output_dir': output_dir,
            'build_stamp': random_string(),
            'current_target': 'virtualbox-amd64'
        }


@pytest.fixture(name='invoke')
def fixture_invoke(build_info):
    """Return a helper that invokes freedom-maker."""

    def _invoke(targets=None, **kwargs):
        """Invoke Freedom Maker."""
        parameters = ['--build-dir', build_info['output_dir']]

        if 'build_stamp' not in kwargs:
            parameters += ['--build-stamp', build_info['build_stamp']]

        command = ['python3', '-m', 'freedommaker'] + parameters + targets
        subprocess.check_call(command)

    return _invoke


def get_built_file(build_info):
    """Return the path of the expected built file."""
    file_name = 'freedombox-unstable_{build_stamp}_all-amd64.vdi.xz' \
        .format(build_stamp=build_info['build_stamp'])

    return os.path.join(build_info['output_dir'], file_name)


def _run(*args, ignore_errors=False):
    """Execute a command."""
    subprocess.run(*args, check=not ignore_errors)


@pytest.mark.skipif(os.environ.get('FM_RUN_VM_TESTS') != 'true',
                    reason='Not requested')
def test_basic_build(build_info, invoke):
    """Test booting and opening SSH shell.

    Also:
      - Output the plinth diagnostic log.
    """
    invoke(['virtualbox-amd64'])

    vm_name = 'freedom-maker-test'
    test_ssh_port = 2222
    first_run_wait_time = 120

    compressed_built_file = get_built_file(build_info)
    built_file = compressed_built_file.rsplit('.', maxsplit=1)[0]

    if not os.path.isfile(built_file):
        subprocess.check_call(
            ['unxz', '--keep', '--force', compressed_built_file])

    passwd_tool = pathlib.Path(__file__).parent / '../passwd_in_image.py'
    _run([
        'sudo', 'python3', passwd_tool, built_file, 'fbx', '--password', 'frdm'
    ])
    try:
        _run([
            'VBoxManage', 'createvm', '--name', vm_name, '--ostype', 'Debian',
            '--register'
        ])
        _run([
            'VBoxManage', 'storagectl', vm_name, '--name', 'SATA Controller',
            '--add', 'sata', '--controller', 'IntelAHCI'
        ])
        _run([
            'VBoxManage', 'storageattach', vm_name, '--storagectl',
            'SATA Controller', '--port', '0', '--device', '0', '--type', 'hdd',
            '--medium', built_file
        ])
        _run([
            'VBoxManage', 'modifyvm', vm_name, '--pae', 'on', '--memory',
            '1024', '--vram', '128', '--nic1', 'nat', '--natpf1',
            ',tcp,,{port},,22'.format(port=test_ssh_port)
        ])
        _run(['VBoxManage', 'startvm', vm_name, '--type', 'headless'])
        time.sleep(first_run_wait_time)

        echo = subprocess.Popen(['echo', 'frdm'], stdout=subprocess.PIPE)
        process = subprocess.Popen([
            'sshpass', '-p', 'frdm', 'ssh', '-o',
            'UserKnownHostsFile=/dev/null', '-o', 'StrictHostKeyChecking=no',
            '-t', '-t', '-p',
            str(test_ssh_port), 'fbx@127.0.0.1', 'sudo plinth --list-modules'
        ],
                                   stdin=echo.stdout)
        process.communicate()
    finally:
        echo = subprocess.Popen(['echo', 'frdm'], stdout=subprocess.PIPE)
        process = subprocess.Popen([
            'sshpass', '-p', 'frdm', 'ssh', '-o',
            'UserKnownHostsFile=/dev/null', '-o', 'StrictHostKeyChecking=no',
            '-t', '-t', '-p',
            str(test_ssh_port), 'fbx@127.0.0.1', 'sudo shutdown now'
        ],
                                   stdin=echo.stdout)
        process.communicate()
        time.sleep(30)
        _run(['VBoxManage', 'modifyvm', vm_name, '--hda', 'none'],
             ignore_errors=True)
        _run(['VBoxManage', 'unregistervm', vm_name, '--delete'],
             ignore_errors=True)
