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

import os
from typing import List, Optional

from PySide6.QtCore import QDir, Signal, Slot
from PySide6.QtGui import QIcon, QPixmap, QTransform
from PySide6.QtWidgets import (QDialog, QFileDialog, QFormLayout, QHBoxLayout,
                               QLabel, QLineEdit, QMessageBox, QPlainTextEdit,
                               QPushButton, QWidget)

from listchooser import ListChooser


def load_file(plaintextedit: QPlainTextEdit, file_name: str) -> None:
    """Load a file into a QPlainTextEdit."""
    s = ''
    if os.path.exists(file_name):
        try:
            with open(file_name, 'r') as f:
                s = f.read()
                f.close()
        except:  # noqa: E722
            pass
    plaintextedit.setPlainText(s)


def choose_existing_file(parent: Optional[QWidget], title: str,
                         mime_types: List[str]) -> Optional[str]:
    """Open a QFileDialog for existing files based on Mime type"""
    dialog = QFileDialog(parent, title)
    dialog.setFileMode(QFileDialog.ExistingFile)
    dialog.setMimeTypeFilters(mime_types)
    if dialog.exec() != QDialog.Accepted:
        return None
    return dialog.selectedFiles()[0]


def choose_existing_file_filter(parent: Optional[QWidget], title: str,
                                filters: List[str]) -> Optional[str]:
    """Open a QFileDialog for existing files based  on Filters"""
    dialog = QFileDialog(parent, title)
    dialog.setFileMode(QFileDialog.ExistingFile)
    dialog.setNameFilters(filters)
    if dialog.exec() != QDialog.Accepted:
        return None
    return dialog.selectedFiles()[0]


def choose_save_file(parent: Optional[QWidget], title: str, mime_types: List[str],
                     default_suffix: str) -> Optional[str]:
    """Open a QFileDialog for saving files"""
    dialog = QFileDialog(parent, title)
    dialog.setFileMode(QFileDialog.AnyFile)
    dialog.setAcceptMode(QFileDialog.AcceptSave)
    dialog.setMimeTypeFilters(mime_types)
    dialog.setDefaultSuffix(default_suffix)
    if dialog.exec() != QDialog.Accepted:
        return None
    return dialog.selectedFiles()[0]


def choose_directory(parent: Optional[QWidget], title: str) -> Optional[str]:
    """Open a QFileDialog for a directory"""
    dialog = QFileDialog(parent, title)
    dialog.setFileMode(QFileDialog.Directory)
    if dialog.exec() != QDialog.Accepted:
        return None
    return dialog.selectedFiles()[0]


def _build_qt_resource_icon(name: str, sizes: List[int]) -> QIcon:
    """Build a standard icon from QStyle resources within QtWidgets"""
    result = QIcon()
    path = ':/qt-project.org/styles/commonstyle/images/'
    for size in sizes:
        result.addPixmap(QPixmap(f'{path}{name}-{size}.png'))
    return result


def qt_resource_icon(name: str) -> QIcon:
    """Return a standard icon from QStyle resources within QtWidgets"""
    return _build_qt_resource_icon(name, [16, 32, 128])


def qt_refresh_icon() -> QIcon:
    return _build_qt_resource_icon('refresh', [24, 32])


def rotate_icon(icon: QIcon, degree: int) -> QIcon:
    """Reassemble a rotated icon"""
    transform = QTransform()
    transform.rotate(degree)
    result = QIcon()
    for size in icon.availableSizes():
        pixmap = icon.pixmap(size)
        result.addPixmap(pixmap.transformed(transform))
    return result


def show_warning(parent: Optional[QWidget], title: str, text: str) -> None:
    """Show a warning"""
    QMessageBox.warning(parent, title, text)


def ask_question(parent: Optional[QWidget], title: str, text: str,
                 default: bool = False) -> bool:
    """Show a question message box warning"""
    default_button = QMessageBox.Yes if default else QMessageBox.No
    buttons = QMessageBox.Yes | QMessageBox.No
    button = QMessageBox.question(parent, title, text, buttons, default_button)
    return button == QMessageBox.Yes


def add_form_row(form_layout: QFormLayout, text: str, widget: QWidget,
                 tool_tip: str) -> None:
    """A a row of label and widget to a QFormLayout with a ToolTip"""
    label = QLabel(text)
    label.setToolTip(tool_tip)
    label.setBuddy(widget)
    widget.setToolTip(tool_tip)
    form_layout.addRow(label, widget)


class PathChooserBase(QWidget):
    """A line edit for files"""

    changed = Signal()

    def __init__(self, parent: Optional[QWidget] = None):
        super(PathChooserBase, self).__init__(parent)
        layout = QHBoxLayout(self)
        layout.setContentsMargins(0, 0, 0, 0)
        self._line_edit = QLineEdit()
        self._line_edit.setClearButtonEnabled(True)
        self._line_edit.setMinimumWidth(250)
        layout.addWidget(self._line_edit)
        chooseButton = QPushButton("Choose...")
        chooseButton.clicked.connect(self.choose)
        layout.addWidget(chooseButton)
        self._line_edit.textChanged.connect(self._changed)

    def set_path(self, path: str) -> None:
        self._line_edit.setText(QDir.toNativeSeparators(path))

    def path(self) -> str:
        return QDir.fromNativeSeparators(self._line_edit.text().strip())

    def is_empty(self) -> bool:
        return not self._line_edit.text()

    @Slot()
    def choose(self) -> None:
        p = self.prompt_file()
        if p:
            self.set_path(p)

    # Overwrite to return a file
    def prompt_file(self) -> Optional[str]:
        pass

    @Slot()
    def _changed(self) -> None:
        self.changed.emit()


class PathChooser(PathChooserBase):
    """A line edit for files using Mime types"""
    def __init__(self, title: str, mime_types,
                 parent: Optional[QWidget] = None):
        super(PathChooser, self).__init__(parent)
        self._title = title
        self._mime_types = mime_types

    def prompt_file(self) -> Optional[str]:
        return choose_existing_file(self, self._title,
                                    self._mime_types)


class FilterPathChooser(PathChooserBase):
    """A line edit for files using filters"""
    def __init__(self, title: str, filters: List[str],
                 parent: Optional[QWidget] = None):
        super(FilterPathChooser, self).__init__(parent)
        self._title = title
        self._filters = filters

    def prompt_file(self) -> Optional[str]:
        return choose_existing_file_filter(self, self._title,
                                           self._filters)


class OutputPathChooser(PathChooserBase):
    """A ListChooser for output directory"""

    def __init__(self, parent: Optional[QWidget] = None):
        super(OutputPathChooser, self).__init__(parent)

    def prompt_file(self) -> Optional[str]:
        return choose_directory(self, "Choose output directory")


class HeaderChooser(ListChooser):
    """A ListChooser for C++ headers"""

    def __init__(self, parent: Optional[QWidget] = None):
        super(HeaderChooser, self).__init__('* Headers', parent)

    def prompt_file(self) -> Optional[str]:
        return choose_existing_file(self, "Choose Header File",
                                    ["text/x-chdr", "text/x-c++hdr"])


class IncludePathChooser(ListChooser):
    """A ListChooser for C++ include paths"""

    def __init__(self, parent: Optional[QWidget] = None):
        super(IncludePathChooser, self).__init__('Include Paths', parent)

    def prompt_file(self) -> Optional[str]:
        return choose_directory(self, "Choose Include Path")
