import shutil
import subprocess
from collections.abc import Iterable
from subprocess import Popen
from typing import Optional

from PyQt5.QtCore import Qt
from PyQt5.QtGui import QIcon, QCursor
from PyQt5.QtWidgets import QDialog, QVBoxLayout, QGroupBox, \
    QLineEdit, QLabel, QGridLayout, QPushButton, QPlainTextEdit, QScrollArea, QFrame, QWidget, QSizePolicy, \
    QHBoxLayout

from bauh.api.abstract.cache import MemoryCache
from bauh.commons.regex import RE_URL
from bauh.view.qt.components import new_spacer
from bauh.view.qt.qt_utils import get_current_screen_geometry
from bauh.view.util.translation import I18n

IGNORED_ATTRS = {'name', '__app__'}


class InfoDialog(QDialog):

    def __init__(self, pkg_info: dict, icon_cache: MemoryCache, i18n: I18n, can_open_url: bool):
        super(InfoDialog, self).__init__()
        self.setWindowTitle(str(pkg_info['__app__']))
        self.i18n = i18n
        self._can_open_url = can_open_url
        layout = QVBoxLayout()
        self.setLayout(layout)

        scroll = QScrollArea(self)
        scroll.setFrameShape(QFrame.NoFrame)
        scroll.setWidgetResizable(True)
        comps_container = QWidget()
        comps_container.setObjectName('root_container')
        comps_container.setLayout(QVBoxLayout())
        scroll.setWidget(comps_container)

        # shows complete field string
        self.text_field = QPlainTextEdit()
        self.text_field.setObjectName('full_field')
        self.text_field.setReadOnly(True)
        comps_container.layout().addWidget(self.text_field)
        self.text_field.hide()

        self.gbox_info = QGroupBox()
        self.gbox_info.setObjectName('fields')
        self.gbox_info.setLayout(QGridLayout())

        comps_container.layout().addWidget(self.gbox_info)

        # THERE ARE CRASHES WITH SOME RARE ICONS ( like insomnia ). IT CAN BE A QT BUG. IN THE MEANTIME, ONLY THE TYPE ICON WILL BE RENDERED
        #
        # icon_data = icon_cache.get(app['__app__'].model.icon_url)
        #
        # if icon_data and icon_data.get('icon'):
        #     self.setWindowIcon(icon_data.get('icon'))
        self.setWindowIcon(QIcon(pkg_info['__app__'].model.get_type_icon_path()))

        for idx, attr in enumerate(sorted(pkg_info.keys())):
            if attr not in IGNORED_ATTRS and pkg_info[attr] is not None:
                i18n_key = pkg_info['__app__'].model.gem_name + '.info.' + attr.lower()
                val = pkg_info[attr]

                if not isinstance(val, str) and isinstance(pkg_info[attr], Iterable):
                    val = ' '.join([str(e).strip() for e in pkg_info[attr] if e])
                    show_val = '\n'.join(['* ' + str(e).strip() for e in pkg_info[attr] if e])
                else:
                    val = str(pkg_info[attr]).strip()
                    show_val = val

                i18n_val = i18n.get(f"{i18n_key}.{val.lower()}")

                if i18n_val:
                    val = i18n_val
                    show_val = val

                text = QLineEdit()
                text.setObjectName('field_value')
                text.setToolTip(show_val)
                text.setText(val)
                text.setCursorPosition(0)
                text.setReadOnly(True)

                label = QLabel(i18n.get(i18n_key, i18n.get(attr.lower(), attr)).capitalize())
                label.setObjectName('field_name')

                self.gbox_info.layout().addWidget(label, idx, 0)
                self.gbox_info.layout().addWidget(text, idx, 1)

                self._gen_show_button(idx=idx, val=show_val)

        layout.addWidget(scroll)

        lower_container = QWidget()
        lower_container.setObjectName('lower_container')
        lower_container.setSizePolicy(QSizePolicy.Minimum, QSizePolicy.Fixed)
        lower_container.setLayout(QHBoxLayout())

        self.bt_back = QPushButton('< {}'.format(self.i18n['back'].capitalize()))
        self.bt_back.setObjectName('back')
        self.bt_back.setVisible(False)
        self.bt_back.setCursor(QCursor(Qt.PointingHandCursor))
        self.bt_back.clicked.connect(self.back_to_info)

        lower_container.layout().addWidget(self.bt_back)
        lower_container.layout().addWidget(new_spacer())

        self.bt_close = QPushButton(self.i18n['close'].capitalize())
        self.bt_close.setObjectName('close')
        self.bt_close.setCursor(QCursor(Qt.PointingHandCursor))
        self.bt_close.clicked.connect(self.close)

        lower_container.layout().addWidget(self.bt_close)
        layout.addWidget(lower_container)
        self.setMinimumWidth(int(self.gbox_info.sizeHint().width() * 1.2))

        screen_height = get_current_screen_geometry().height()
        self.setMaximumHeight(int(screen_height * 0.8))
        self.adjustSize()

    @staticmethod
    def open_url(url: str):
        Popen(["xdg-open", url], stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL, stdin=subprocess.DEVNULL)

    def _show_full_field_val(self, val: str):
        self.gbox_info.hide()
        self.bt_back.setVisible(True)
        self.text_field.show()
        self.text_field.setPlainText(val)

    def _gen_show_button(self, idx: int, val: str):

        is_url = self._can_open_url and bool(RE_URL.match(val)) if val else False

        if is_url:
            bt_label = self.i18n["manage_window.info.open_url"]

            def _show_field():
                self.open_url(val)
        else:
            bt_label = self.i18n["show"].capitalize()

            def _show_field():
                self._show_full_field_val(val)

        bt_full_field = QPushButton(bt_label)
        bt_full_field.setObjectName("show")
        bt_full_field.setCursor(QCursor(Qt.PointingHandCursor))
        bt_full_field.clicked.connect(_show_field)
        self.gbox_info.layout().addWidget(bt_full_field, idx, 2)

    def back_to_info(self):
        self.text_field.setPlainText("")
        self.text_field.hide()
        self.gbox_info.show()
        self.bt_back.setVisible(False)
