# Copyright (C) 2022 The Qt Company Ltd.
# SPDX-License-Identifier: LicenseRef-Qt-Commercial

import os
import sys
from typing import List, Tuple
import warnings

from PySide6.QtCore import QByteArray, QDir, QProcess, QUrl
from PySide6.QtGui import QDesktopServices

from options import Options


def qprocess_output(output: QByteArray) -> str:
    """Convert the output of QProcess into a str"""
    return bytes(output).decode("utf-8").replace('\r', '')


def _os_edit_file(path: str, tool: str = 'kate') -> None:
    """Edit a file (OS implementation)"""
    editor = os.environ.get('EDITOR')
    if not editor:
        editor = tool if sys.platform != 'win32' else 'notepad'
    QProcess.startDetached(editor, [QDir.toNativeSeparators(path)])


def launch_creator(path: str) -> None:
    """Launch Qt Creator with a file"""
    QProcess.startDetached(Options.creator_path(),
                           ['-client', QDir.toNativeSeparators(path)])


def edit_file(path: str) -> None:
    """Edit  a file"""
    if Options.use_creator():
        launch_creator(path)
    else:
        _os_edit_file(path)


def launch_file(path: str) -> None:
    """Launch a file or directory"""
    # Avoid windows prompting for app
    if sys.platform == 'win32' and os.path.isfile(path):
        edit_file(path)
    else:
        QDesktopServices.openUrl(QUrl.fromLocalFile(path))


def run_process_output(binary: str, arguments: List[str],
                       work_dir: str = None) -> Tuple[QProcess.ExitStatus, int, str, str, str]:
    """Run a command line process and capture its output. Returns
       a tuple of
       (QProcess.ExitStatus, exit_code, stdout, stderr, error_message)"""
    process = QProcess()
    if work_dir:
        process.setWorkingDirectory(work_dir)
    process.start(binary, arguments)
    command_string = '{} {}'.format(binary, ' '.join(arguments))
    print('running', command_string)
    if not process.waitForStarted():
        error_string = process.errorString()
        error = f"Cannot start {command_string}: {error_string}"
        warnings.warn(error)
        return (QProcess.CrashExit, -1, '', '', error)
    if not process.waitForFinished():
        process.kill()
        error = "{} timed out".format(command_string)
        warnings.warn(error)
        return (QProcess.CrashExit, -1, '', '', error)

    error = None
    exit_status = process.exitStatus()
    exit_code = process.exitCode()
    stdout = qprocess_output(process.readAllStandardOutput())
    stderr = qprocess_output(process.readAllStandardError())
    if exit_status != QProcess.NormalExit:
        error = "{} crashed".format(command_string)
    elif exit_code != 0:
        error = "{} returned {}".format(command_string, exit_code)
    if error:
        warnings.warn(error)
    return (exit_status, exit_code, stdout, stderr, error)
