import sys
from PyQt5 import uic, QtCore
from PyQt5.QtWidgets import QTableWidgetItem, QTableView, QHeaderView

from restatic.restic.prune import ResticPruneThread
from restatic.restic.list import ResticListThread
from restatic.restic.check import ResticCheckThread
from restatic.restic.mount import ResticMountThread
from restatic.restic.umount import ResticUmountThread
from restatic.views.extract_dialog import ExtractDialog
from restatic.utils import get_asset, choose_folder_dialog
from restatic.models import BackupProfileMixin, ArchiveModel

uifile = get_asset("UI/archivetab.ui")
ArchiveTabUI, ArchiveTabBase = uic.loadUiType(
    uifile, from_imports=True, import_from="restatic.views"
)


class ArchiveTab(ArchiveTabBase, ArchiveTabUI, BackupProfileMixin):
    prune_intervals = ["hour", "day", "week", "month", "year"]

    def __init__(self, parent=None):
        super().__init__(parent)
        self.setupUi(parent)
        self.mount_point = None

        header = self.archiveTable.horizontalHeader()
        header.setVisible(True)
        header.setSectionResizeMode(0, QHeaderView.ResizeToContents)
        header.setSectionResizeMode(1, QHeaderView.ResizeToContents)
        header.setSectionResizeMode(2, QHeaderView.ResizeToContents)
        header.setSectionResizeMode(3, QHeaderView.Stretch)
        header.setStretchLastSection(True)

        if sys.platform != "darwin":
            self._set_status("")  # Set platform-specific hints.

        self.archiveTable.setSelectionBehavior(QTableView.SelectRows)
        self.archiveTable.setEditTriggers(QTableView.NoEditTriggers)
        self.archiveTable.setAlternatingRowColors(True)

        # Populate pruning options from database
        for i in self.prune_intervals:
            getattr(self, f"prune_{i}").setValue(getattr(self.profile(), f"prune_{i}"))
            getattr(self, f"prune_{i}").valueChanged.connect(self.save_prune_setting)

        self.mountButton.clicked.connect(self.mount_action)
        self.listButton.clicked.connect(self.list_action)
        self.pruneButton.clicked.connect(self.prune_action)
        self.checkButton.clicked.connect(self.check_action)
        self.extractButton.clicked.connect(self.extract_action)

        self.populate_from_profile()

    def _set_status(self, text):
        self.mountErrors.setText(text)
        self.mountErrors.repaint()

    def _toggle_all_buttons(self, enabled=True):
        self.checkButton.setEnabled(enabled)
        self.listButton.setEnabled(enabled)
        self.pruneButton.setEnabled(enabled)
        self.mountButton.setEnabled(enabled)

    def populate_from_profile(self):

        profile = self.profile()

        if profile.repo is not None:
            self.currentRepoLabel.setText(profile.repo.url)
            self.archiveTable.setRowCount(0)  # clear the table

            for row, archive in enumerate(
                ArchiveModel.select().where(ArchiveModel.repo == profile.repo)
            ):
                self.archiveTable.insertRow(row)
                formatted_time = str(archive.time)
                # formatted_time = archive.time.strftime("%Y-%m-%d %H:%M") # FIXME
                self.archiveTable.setItem(row, 0, QTableWidgetItem(archive.name))
                self.archiveTable.setItem(row, 1, QTableWidgetItem(formatted_time))
                self.archiveTable.setItem(row, 2, QTableWidgetItem(archive.hostname))
            # self.archiveTable.setRowCount(len(archives))
            self._toggle_all_buttons(enabled=True)

        else:
            self.archiveTable.setRowCount(0)
            self.currentRepoLabel.setText("N/A")
            self._toggle_all_buttons(enabled=False)

    def check_action(self):
        params = ResticCheckThread.prepare(self.profile())
        if params["ok"]:
            thread = ResticCheckThread(params["cmd"], params, parent=self)
            thread.updated.connect(self._set_status)
            thread.result.connect(self.check_result)
            self._toggle_all_buttons(False)
            thread.start()

    def check_result(self, result):
        if result["returncode"] == 0:
            self._toggle_all_buttons(True)

    def prune_action(self):
        params = ResticPruneThread.prepare(self.profile())
        if params["ok"]:
            thread = ResticPruneThread(params["cmd"], params, parent=self)
            thread.updated.connect(self._set_status)
            thread.result.connect(self.prune_result)
            self._toggle_all_buttons(False)
            thread.start()

    def prune_result(self, result):
        if result["returncode"] == 0:
            self._set_status("Pruning finished.")
            self.list_action()
        else:
            self._toggle_all_buttons(True)

    def list_action(self):
        params = ResticListThread.prepare(self.profile())
        if params["ok"]:
            thread = ResticListThread(params["cmd"], params, parent=self)
            thread.updated.connect(self._set_status)
            thread.result.connect(self.list_result)
            self._toggle_all_buttons(False)
            thread.start()

    def list_result(self, result):
        self._toggle_all_buttons(True)
        if result["returncode"] == 0:
            self._set_status("Refreshed snapshots.")
            self.populate_from_profile()

    def mount_action(self):
        profile = self.profile()
        params = ResticMountThread.prepare(profile)
        if not params["ok"]:
            self._set_status(params["message"])
            return

        # Conditions are met (restic binary available, etc)
        row_selected = self.archiveTable.selectionModel().selectedRows()
        if row_selected:
            snapshot_cell = self.archiveTable.item(row_selected[0].row(), 3)
            if snapshot_cell:
                snapshot_name = snapshot_cell.text()
                params["cmd"][-1] += f"::{snapshot_name}"

        def receive():
            mount_point = dialog.selectedFiles()
            if mount_point:
                params["cmd"].append(mount_point[0])
                self.mount_point = mount_point[0]
                if params["ok"]:
                    self._toggle_all_buttons(False)
                    thread = ResticMountThread(params["cmd"], params, parent=self)
                    thread.updated.connect(self.mountErrors.setText)
                    thread.result.connect(self.mount_result)
                    thread.start()

        dialog = choose_folder_dialog(self, "Choose Mount Point")
        dialog.open(receive)

    def mount_result(self, result):
        self._toggle_all_buttons(True)
        if result["returncode"] == 0:
            self._set_status("Mounted successfully.")
            self.mountButton.setText("Unmount")
            self.mountButton.clicked.disconnect()
            self.mountButton.clicked.connect(self.umount_action)
        else:
            self.mount_point = None

    def umount_action(self):
        if self.mount_point is not None:
            profile = self.profile()
            params = ResticUmountThread.prepare(profile)
            if not params["ok"]:
                self._set_status(params["message"])
                return

            if self.mount_point in params["active_mount_points"]:
                params["cmd"].append(self.mount_point)
                thread = ResticUmountThread(params["cmd"], params, parent=self)
                thread.updated.connect(self.mountErrors.setText)
                thread.result.connect(self.umount_result)
                thread.start()
            else:
                self._set_status("Mount point not active. Try restarting Restatic.")
                return

    def umount_result(self, result):
        self._toggle_all_buttons(True)
        if result["returncode"] == 0:
            self._set_status("Un-mounted successfully.")
            self.mountButton.setText("Mount")
            self.mountButton.clicked.disconnect()
            self.mountButton.clicked.connect(self.mount_action)
            self.mount_point = None

    def save_prune_setting(self, new_value):
        profile = self.profile()
        for i in self.prune_intervals:
            setattr(profile, f"prune_{i}", getattr(self, f"prune_{i}").value())
        profile.save()

    def extract_action(self):
        window = ExtractDialog()
        window.setParent(self, QtCore.Qt.Sheet)
        window.show()