from __future__ import annotations

from pathlib import Path

from PySide6.QtCore import Qt, QUrl
from PySide6.QtGui import QDesktopServices
from PySide6.QtWidgets import (
    QCheckBox,
    QDialog,
    QFileDialog,
    QHBoxLayout,
    QLabel,
    QListWidget,
    QListWidgetItem,
    QMessageBox,
    QPushButton,
    QVBoxLayout,
)

from mi100.services.backup_service import BackupService


class BackupDialog(QDialog):
    def __init__(self, backup_service: BackupService, parent=None):
        super().__init__(parent)
        self.backup_service = backup_service
        self.setWindowTitle("Резервні копії")
        self.setModal(True)
        self.resize(760, 520)
        self.restore_completed = False
        self._build_ui()
        self._reload_list()

    def _build_ui(self) -> None:
        root = QVBoxLayout(self)
        root.setContentsMargins(14, 14, 14, 14)
        root.setSpacing(10)

        title = QLabel("Резервні копії / Відновлення / Експорт бази")
        title.setStyleSheet("font-size: 12pt; font-weight: 700;")
        root.addWidget(title)

        folder_row = QHBoxLayout()
        self.backup_path_label = QLabel()
        self.backup_path_label.setStyleSheet("font-weight: 600;")
        self.btn_choose_folder = QPushButton("Обрати папку")
        folder_row.addWidget(QLabel("Папка резервних копій:"))
        folder_row.addWidget(self.backup_path_label, 1)
        folder_row.addWidget(self.btn_choose_folder)
        root.addLayout(folder_row)

        options_row = QHBoxLayout()
        self.include_docs = QCheckBox("Документи")
        self.include_docs.setChecked(True)
        self.include_media = QCheckBox("Медіафайли")
        self.include_media.setChecked(True)
        options_row.addWidget(QLabel("У нову резервну копію включати:"))
        options_row.addWidget(self.include_docs)
        options_row.addWidget(self.include_media)
        options_row.addStretch(1)
        root.addLayout(options_row)

        actions = QHBoxLayout()
        self.btn_create = QPushButton("Створити резервну копію")
        self.btn_export = QPushButton("Експорт бази")
        self.btn_restore = QPushButton("Відновити з резервної копії")
        self.btn_open_folder = QPushButton("Відкрити папку")
        for btn in (self.btn_create, self.btn_export, self.btn_restore, self.btn_open_folder):
            actions.addWidget(btn)
        root.addLayout(actions)

        subtitle = QLabel("Доступні резервні копії")
        subtitle.setStyleSheet("font-weight: 700;")
        root.addWidget(subtitle)

        self.backup_list = QListWidget()
        self.backup_list.setSelectionMode(QListWidget.SingleSelection)
        root.addWidget(self.backup_list, 1)

        bottom = QHBoxLayout()
        bottom.addStretch(1)
        self.btn_close = QPushButton("Закрити")
        bottom.addWidget(self.btn_close)
        root.addLayout(bottom)

        self.btn_choose_folder.clicked.connect(self._choose_folder)
        self.btn_create.clicked.connect(self._create_backup)
        self.btn_export.clicked.connect(self._export_db)
        self.btn_restore.clicked.connect(self._restore_backup)
        self.btn_open_folder.clicked.connect(self._open_folder)
        self.btn_close.clicked.connect(self.accept)

    def _reload_list(self) -> None:
        self.backup_path_label.setText(str(self.backup_service.get_backup_dir()))
        self.backup_list.clear()
        for path in self.backup_service.list_backups():
            item = QListWidgetItem(path.name)
            item.setData(Qt.UserRole, str(path))
            self.backup_list.addItem(item)

    def _selected_backup_path(self) -> Path | None:
        item = self.backup_list.currentItem()
        if not item:
            return None
        return Path(str(item.data(Qt.UserRole)))


    def _choose_folder(self) -> None:
        current = str(self.backup_service.get_backup_dir())
        folder = QFileDialog.getExistingDirectory(self, "Оберіть папку для резервних копій", current)
        if not folder:
            return
        self.backup_service.set_backup_dir(folder)
        self._reload_list()

    def _create_backup(self) -> None:
        try:
            path = self.backup_service.create_backup(
                include_documents=self.include_docs.isChecked(),
                include_media=self.include_media.isChecked(),
            )
        except Exception as exc:
            QMessageBox.critical(self, "Резервна копія", f"Не вдалося створити резервну копію:\n{exc}")
            return
        self._reload_list()
        QMessageBox.information(self, "Резервна копія", f"Резервну копію створено:\n{path}")

    def _export_db(self) -> None:
        suggested = self.backup_service.paths["backups"] / "mi100_database_export.sqlite"
        filename, _ = QFileDialog.getSaveFileName(
            self,
            "Експорт бази даних",
            str(suggested),
            "SQLite база (*.sqlite *.db);;Усі файли (*)",
        )
        if not filename:
            return
        try:
            path = self.backup_service.export_database(Path(filename))
        except Exception as exc:
            QMessageBox.critical(self, "Експорт бази", f"Не вдалося експортувати базу:\n{exc}")
            return
        QMessageBox.information(self, "Експорт бази", f"Базу даних експортовано:\n{path}")

    def _restore_backup(self) -> None:
        path = self._selected_backup_path()
        if path is None:
            path_str, _ = QFileDialog.getOpenFileName(
                self,
                "Оберіть резервну копію",
                str(self.backup_service.get_backup_dir()),
                "ZIP архів (*.zip)",
            )
            if not path_str:
                return
            path = Path(path_str)

        msg = QMessageBox(self)
        msg.setWindowTitle("Відновлення з резервної копії")
        msg.setIcon(QMessageBox.Warning)
        msg.setText(
            "Програма відновить дані з резервної копії.\n"
            "Перед цим буде автоматично створено страхувальну резервну копію поточного стану.\n\n"
            "Після відновлення програму потрібно буде закрити й запустити знову."
        )
        msg.setStandardButtons(QMessageBox.Yes | QMessageBox.No)
        msg.button(QMessageBox.Yes).setText("Відновити")
        msg.button(QMessageBox.No).setText("Скасувати")
        if msg.exec() != QMessageBox.Yes:
            return

        try:
            self.backup_service.restore_from_backup(path)
        except Exception as exc:
            QMessageBox.critical(self, "Відновлення", f"Не вдалося відновити резервну копію:\n{exc}")
            return

        self.restore_completed = True
        QMessageBox.information(
            self,
            "Відновлення завершено",
            "Дані відновлено. Програма зараз закриється, після чого її потрібно запустити знову.",
        )
        self.accept()

    def _open_folder(self) -> None:
        folder = self.backup_service.get_backup_dir()
        QDesktopServices.openUrl(QUrl.fromLocalFile(str(folder)))
