import uuid
import os
import subprocess
import test
from urllib.parse import urlparse
from os import makedirs
from os.path import exists, join
from PySide6.QtCore import QSettings, QUuid, QUrl, QJsonValue

from helpers.SpaceHelper import get_space_id, get_personal_space_id
from helpers.ConfigHelper import get_config, set_config, is_windows
from helpers.SyncHelper import listen_sync_status_for_item
from helpers.api.utils import url_join
from helpers.UserHelper import get_displayname_for_user
from helpers.api import provisioning
from helpers.AppHelper import create_app_session


def substitute_inline_codes(value):
    value = value.replace('%local_server%', get_config('localBackendUrl'))
    value = value.replace('%client_root_sync_path%', get_config('clientRootSyncPath'))
    value = value.replace('%current_user_sync_path%', get_config('currentUserSyncPath'))
    value = value.replace(
        '%local_server_hostname%', urlparse(get_config('localBackendUrl')).netloc
    )
    value = value.replace('%home%', get_config('home_dir'))

    return value


def get_client_details(table):
    client_details = {
        'server': '',
        'user': '',
        'password': '',
        'sync_folder': '',
    }
    for key, value in table.items():
        value = substitute_inline_codes(value)
        if key == 'server':
            client_details.update({'server': value})
        elif key == 'user':
            client_details.update({'user': value})
        elif key == 'password':
            client_details.update({'password': value})
        elif key == 'sync_folder':
            client_details.update({'sync_folder': value})
    return client_details


def create_user_sync_path(username):
    # '' at the end adds '/' to the path
    user_sync_path = join(get_config('clientRootSyncPath'), username, '')

    if not exists(user_sync_path):
        makedirs(user_sync_path)

    set_current_user_sync_path(user_sync_path)
    return user_sync_path


def create_space_path(username, space='Personal'):
    user_sync_path = create_user_sync_path(username)
    space_path = join(user_sync_path, space, '')
    if not exists(space_path):
        makedirs(space_path)
    return space_path


def set_current_user_sync_path(sync_path):
    set_config('currentUserSyncPath', sync_path)


def get_resource_path(resource='', user='', space=''):
    sync_path = get_config('currentUserSyncPath')
    if user:
        sync_path = user
    space = space or get_config('syncConnectionName')
    sync_path = join(sync_path, space)
    sync_path = join(get_config('clientRootSyncPath'), sync_path)
    resource = resource.replace(sync_path, '').strip('/').strip('\\')
    return join(
        sync_path,
        resource,
    )


def parse_username_from_sync_path(sync_path):
    return sync_path.split('/').pop()


def get_temp_resource_path(resource_name):
    return join(get_config('tempFolderPath'), resource_name)


def get_current_user_sync_path():
    return get_config('currentUserSyncPath')


def start_client():
    create_app_session()


def get_polling_interval():
    polling_interval = '''
[QSfera]
remotePollInterval={polling_interval}
'''
    args = {'polling_interval': 5000}
    polling_interval = polling_interval.format(**args)
    return polling_interval


def generate_account_config(users, space='Personal'):
    sync_paths = {}
    settings = QSettings(get_config('clientConfigFile'), QSettings.Format.IniFormat)
    users_uuids = {}
    server_url = get_config('localBackendUrl')
    capabilities = provisioning.get_capabilities()
    capabilities_variant = QJsonValue(capabilities).toVariant()

    for idx, username in enumerate(users):
        users_uuids[username] = QUuid.createUuid()
        settings.beginGroup("Accounts")
        settings.beginWriteArray(str(idx + 1), len(users))

        settings.setValue("capabilities", capabilities_variant)
        settings.setValue("default_sync_root", create_user_sync_path(username))
        settings.setValue("uuid", users_uuids[username])
        settings.setValue("display-name", get_displayname_for_user(username))
        settings.setValue("url", server_url)
        settings.setValue("userExplicitlySignedOut", 'false')

        settings.endArray()
        settings.setValue("size", len(users))
        settings.endGroup()

    settings.beginGroup("Folders")
    for idx, username in enumerate(users):
        sync_path = create_space_path(username, space)
        settings.beginWriteArray(str(idx + 1), len(users))

        if space == 'Personal':
            space_id = get_personal_space_id(username)
        else:
            space_id = get_space_id(space, username)
        dav_endpoint = QUrl(url_join(server_url, '/dav/spaces/', space_id))
        settings.setValue("spaceId", space_id)
        settings.setValue("accountUUID", users_uuids[username])
        settings.setValue("davUrl", dav_endpoint)
        settings.setValue("deployed", 'false')
        settings.setValue("displayString", get_config('syncConnectionName'))
        settings.setValue("ignoreHiddenFiles", 'true')
        settings.setValue("localPath", sync_path)
        settings.setValue("paused", 'false')
        settings.setValue("priority", '50')
        if is_windows():
            settings.setValue("virtualFilesMode", 'cfapi')
        else:
            settings.setValue("virtualFilesMode", 'off')
        settings.setValue("journalPath", ".sync_journal.db")
        settings.endArray()
        settings.setValue("size", len(users))
        sync_paths.update({username: sync_path})

    settings.endGroup()

    settings.sync()
    return sync_paths


def setup_client(username, space='Personal'):
    set_config('syncConnectionName', space)
    sync_paths = generate_account_config([username], space)
    start_client()
    for _, sync_path in sync_paths.items():
        listen_sync_status_for_item(sync_path)


def generate_uuidv4():
    return str(uuid.uuid4())


# sometimes the keyring is locked during the test execution, and we need to unlock it
def unlock_keyring():
    if is_windows():
        return

    stdout, stderr, _ = run_sys_command(
        [
            'busctl',
            '--user',
            'get-property',
            'org.freedesktop.secrets',
            '/org/freedesktop/secrets/collection/login',
            'org.freedesktop.Secret.Collection',
            'Locked',
        ]
    )
    output = ''
    if stdout:
        output = stdout.decode('utf-8')
    if stderr:
        output = stderr.decode('utf-8')

    if not output.strip().endswith('false'):
        test.log('Unlocking keyring...')
        password = os.getenv('VNC_PW')
        command = f'echo -n "{password}" | gnome-keyring-daemon -r -d --unlock'
        stdout, stderr, returncode = run_sys_command(command, True)
        if stdout:
            output = stdout.decode('utf-8')
        if stderr:
            output = stderr.decode('utf-8')
        if returncode:
            test.log(f'Failed to unlock keyring:\n{output}')


def run_sys_command(command=None, shell=False):
    cmd = subprocess.run(
        command,
        shell=shell,
        stdout=subprocess.PIPE,
        stderr=subprocess.PIPE,
        check=False,
    )
    return cmd.stdout, cmd.stderr, cmd.returncode
