import os
from PyQt5.QtWidgets import QComboBox, QFrame, QGroupBox, QHBoxLayout, QLabel, QListWidget, QListWidgetItem, QSpacerItem, QSplitter, QStackedLayout, QAbstractItemView, QTextEdit, QVBoxLayout, QWidget, QGridLayout, QTreeView, QHeaderView
from PyQt5.QtGui import QPixmap
from PyQt5.QtCore import QItemSelectionModel, Qt, QSettings, QSize, pyqtSignal

from file_handler import FileHandler, ItemDescriptor
from plot_screen import PlotScreen
import communicator as comm
import constants as cnst
from tree_model import NixTreeItem, TagTreeItem, TreeModel, TreeType

class CentralWidget(QWidget):
    
    def __init__(self, parent=None) -> None:
        super().__init__(parent=parent)
        
        self._splash = SplashScreen()
        self._file_view = FileView(self)
        self._plot_screen = PlotScreen(self)
        self._plot_screen.close_signal.connect(self.on_plot_close)
        self._stack = QStackedLayout(self)
        self._stack.addWidget(self._splash)
        self._stack.addWidget(self._file_view)
        self._stack.addWidget(self._plot_screen)
        self.setLayout(self._stack)

    def show_file_content(self):
        self._stack.setCurrentIndex(1)
        self._file_view.update()

    def plot_item(self, item):
        self._stack.setCurrentIndex(2)
        self._plot_screen.plot(item)

    def on_plot_close(self):
        self._stack.setCurrentIndex(1)

    def reset(self):
        self._file_view.reset()
        self._splash.reset()
        self._stack.setCurrentIndex(0)


class FileView(QWidget):
    icon_size = QSize(30, 30)
    def __init__(self, parent=None) -> None:
        super().__init__(parent=parent)
        self._file_handler = FileHandler()
        
        vbox = QVBoxLayout()
        self.setLayout(vbox)
        
        main_splitter = QSplitter(Qt.Vertical)
        self.layout().addWidget(main_splitter)
        
        self._info = EntityInfo(self)
        main_splitter.addWidget(self._info)
       
        self._data_tree = QTreeView(self)
        self._data_tree.expanded.connect(self.dataTreeResize)
        self._data_tree.collapsed.connect(self.dataTreeResize)
        self._data_tree.setAlternatingRowColors(True)
        self._data_tree.setUniformRowHeights(True)  # Allows for scrolling optimizations.
        self._data_tree.setWindowTitle("Data Tree")
        self._data_tree.setIconSize(self.icon_size)
        self._data_tree.setSelectionBehavior(QAbstractItemView.SelectItems)
        self._data_tree.setSelectionMode(QAbstractItemView.SingleSelection)
        header = self._data_tree.header()
        header.setStretchLastSection(False)
        header.setSectionResizeMode(1, QHeaderView.ResizeToContents)
        header.setSectionResizeMode(2, QHeaderView.ResizeToContents)
        header.setSectionResizeMode(0, QHeaderView.Stretch)

        self._tree_type_combo = QComboBox()
        self._tree_type_combo.adjustSize()
        self._tree_type_combo.addItems([TreeType.Data.value, TreeType.Full.value, TreeType.Metadata.value])
        self._tree_type_combo.currentTextChanged.connect(self.update)
        
        hbox = QHBoxLayout()
        hbox.addWidget(QLabel("Tree type:"))
        hbox.addWidget(self._tree_type_combo)
        hbox.addStretch()
        data_group = QGroupBox("Data")
        data_vbox = QVBoxLayout()
        data_vbox.setContentsMargins(1, 10, 1, 1)
        
        data_vbox.addLayout(hbox)
        data_vbox.addWidget(self._data_tree)
        data_group.setLayout(data_vbox)
        
        main_splitter.addWidget(data_group)
        main_splitter.setSizes([200, 600])
        vbox.addWidget(main_splitter)

    def metadataTreeResize(self, index):
        self._mdata_tree.resizeColumnToContents(index.column())
    
    def dataTreeResize(self, index):
        self._data_tree.resizeColumnToContents(index.column())
    
    def dataTreeSelection(self, current_index, last_index):
        if not current_index.isValid():
            return
        item = current_index.internalPointer()
        comm.communicator.item_selected.emit(item)
        self._info.setEntityInfo(item.node_descriptor)

    def update(self):
        tt = TreeType.Data
        if self._tree_type_combo.currentText() == TreeType.Data.value:
            tt = TreeType.Data
        elif self._tree_type_combo.currentText() == TreeType.Full.value:
            tt = TreeType.Full
        elif self._tree_type_combo.currentText() == TreeType.Metadata.value:
            tt = TreeType.Metadata
        self._info.setEntityInfo(None)
        data_model = TreeModel(self._file_handler, tt)
        self._data_tree.setModel(data_model)
        selection_model = QItemSelectionModel(data_model)
        self._data_tree.setSelectionModel(selection_model)
        selection_model.currentChanged.connect(self.dataTreeSelection)
        for i in range(data_model.columnCount(None)):
            self._data_tree.resizeColumnToContents(i)
        self._info.setFileInfo(self._file_handler.file_descriptor)
        
    def reset(self):
        pass


class EntityInfo(QWidget):
    icon_size = QSize(30, 30)

    def __init__(self, parent):
        super().__init__(parent=parent)
        self._file_handler = FileHandler()
        self.setLayout(QHBoxLayout())
        
        self._metadata_tree = QTreeView()
        # self._metadata_tree.expanded.connect(self.metadataTreeResize)
        # self._metadata_tree.collapsed.connect(self.metadataTreeResize)
        self._metadata_tree.setAlternatingRowColors(True)
        self._metadata_tree.setUniformRowHeights(True)  # Allows for scrolling optimizations.
        self._metadata_tree.setWindowTitle("Metadata Tree")
        self._metadata_tree.setIconSize(self.icon_size)
        mheader = self._metadata_tree.header()
        mheader.setStretchLastSection(False)
        mheader.setSectionResizeMode(1, QHeaderView.ResizeToContents)
        mheader.setSectionResizeMode(2, QHeaderView.ResizeToContents)
        mheader.setSectionResizeMode(0, QHeaderView.Stretch)
        
        mdata_grp = QGroupBox("Metadata")
        mdata_grp.setLayout(QVBoxLayout())
        mdata_grp.layout().setContentsMargins(1, 10, 1, 1)
        mdata_grp.layout().addWidget(self._metadata_tree)
        
        file_info_grp = QGroupBox("File info")
        file_info_grp.setLayout(QVBoxLayout())
        file_info_grp.layout().setContentsMargins(1, 10, 1, 1)
        self._file_info = QTextEdit("File information")
        self._file_info.setEnabled(True)
        self._file_info.setTextInteractionFlags(Qt.TextSelectableByKeyboard | Qt.TextSelectableByMouse)
        self._file_info.setFrameShape(QFrame.NoFrame)
        self._file_info.setLineWrapMode(QTextEdit.WidgetWidth)
        file_info_grp.layout().addWidget(self._file_info)

        entity_info_grp = QGroupBox("Entity info")
        entity_info_grp.setLayout(QVBoxLayout())
        entity_info_grp.layout().setContentsMargins(1, 10, 1, 1)
        self._entity_info = QTextEdit("Entity information")
        self._file_info.setEnabled(True)
        self._file_info.setTextInteractionFlags(Qt.TextSelectableByKeyboard | Qt.TextSelectableByMouse)
        self._file_info.setFrameShape(QFrame.NoFrame)
        self._file_info.setLineWrapMode(QTextEdit.WidgetWidth)
        entity_info_grp.layout().addWidget(self._entity_info)
 
        self._splitter = QSplitter(Qt.Horizontal)
        self._splitter.addWidget(file_info_grp)
        self._splitter.addWidget(entity_info_grp)
        self._splitter.addWidget(mdata_grp)
        self._splitter.setSizes([200, 400, 0])
        self._splitter.setStretchFactor(0, 0)
        self._splitter.setStretchFactor(1, 1)
        self._splitter.setStretchFactor(2, 1)
        
        self.layout().addWidget(self._splitter)
        

    def setFileInfo(self, file_info):
        if file_info is not None:
            self._file_info.setText(file_info.toHtml())
            
    def setEntityInfo(self, entity_info):
        if entity_info is None or not isinstance(entity_info, ItemDescriptor):
            self._splitter.setSizes([200, 400, 0])
            self._entity_info.setText("")
            self._metadata_tree.setModel(None)
            return

        if entity_info.metadata_id is not None:
            self._splitter.setSizes([200, 400, 400])
        else:
            self._splitter.setSizes([200, 400, 0])
        self._entity_info.setText(entity_info.to_html())
        metadata_model = TreeModel(self._file_handler, TreeType.Metadata, root_section_id=entity_info.metadata_id)
        self._metadata_tree.setModel(metadata_model)
        for i in range(metadata_model.columnCount(None)):
            self._metadata_tree.resizeColumnToContents(i)


class SplashScreen(QWidget):
    keyPressed = pyqtSignal(int)

    def __init__(self, parent=None) -> None:
        super().__init__(parent=parent)
        #self.setStyleSheet("background-color: white;")

        layout = QGridLayout()
        layout.setColumnStretch(0, 1)
        layout.setColumnStretch(1, 0)
        layout.setColumnStretch(2, 1)
        layout.setRowStretch(0, 1)
        layout.setRowStretch(2, 1)
        self.setLayout(layout)
        
        label = QLabel()
        label.setPixmap(QPixmap("./icons/nixview_transparent.png"))
        
        label.setMaximumWidth(300)
        label.setAlignment(Qt.AlignCenter)
        layout.addWidget(label, 1, 1)
        
        frame = QFrame()
        l  = QVBoxLayout()
        l.addWidget(QLabel("Recently opened files:"))
        self._file_list = QListWidget(self)
        self._file_list.setSelectionMode(QAbstractItemView.SingleSelection)
        self._file_list.itemClicked.connect(self._on_file_clicked)
        self.keyPressed.connect(self._on_key_pressed)
        l.addWidget(self._file_list)
        frame.setLayout(l)
        layout.addWidget(frame, 3, 1)
        self._file_map = {}
        self._read_recent_files()
    
    def keyPressEvent(self, event):
        super(SplashScreen, self).keyPressEvent(event)
        if event.key() == Qt.Key_Return:
            self.keyPressed.emit(event.key())
    
    def _create_short_filename(self, original, index, max_len=40):
        short = original
        parts = original.split(os.sep)
        if len(parts) == 1:
            short = "%i: %s" % (index, short[:max_len])
        else:
            post = parts[-1]
            if len(post) > max_len - 4:
                post = post[:max_len - 4]
                short = str("%i: " % index) + "... " + post
            else:
                short = str("%i: " % index) + " ... ".join([original[:max_len - len(post) - 4], post])
        return short
        
    def _read_recent_files(self):
        settings = QSettings(cnst.organization, cnst.application)
        filenames = settings.value(cnst.settings_recent_files_key, [])
        del settings

        for i, f in enumerate(filenames):
            shortname = self._create_short_filename(f, i + 1, max_len=38)
            self._file_map[shortname] = f
            item = QListWidgetItem(shortname)
            item.setToolTip(f)
            self._file_list.addItem(item)

    def reset(self):
        self._file_list.clear()
        self._read_recent_files() 

    def _on_file_clicked(self, item):
        comm.communicator.open_recent.emit(self._file_map[item.text()])

    def _on_key_pressed(self, key):
        item = self._file_list.currentItem()
        if item is not None and key == Qt.Key_Return:
            comm.communicator.open_recent.emit(self._file_map[item.text()])