from __future__ import annotations

from PySide6.QtCore import Qt, QUrl
from PySide6.QtGui import QPixmap, QGuiApplication, QDesktopServices
from PySide6.QtWidgets import (
    QDialog, QVBoxLayout, QHBoxLayout, QLabel, QPushButton,
    QTextEdit, QLineEdit, QTabWidget, QWidget,
    QGridLayout, QFileDialog, QFrame, QCheckBox, QListWidget, QListWidgetItem, QMessageBox, QComboBox, QTableWidget, QTableWidgetItem, QHeaderView
)

from mi100.repository import Repo
from mi100.licensing.license_manager import LicenseManager
from mi100.ui.license_dialog import ActivationDialog
from mi100.services.backup_service import BackupService

BTN_GREEN = "QPushButton{background:#4FAF7A;color:#FFFFFF;border:1px solid #459E6E;border-radius:4px;padding:4px 10px;font-weight:600;}QPushButton:hover{background:#459E6E;}"
BTN_GRAY = "QPushButton{background:#EBEBEB;color:#374151;border:1px solid #D7D7D7;border-radius:4px;padding:4px 10px;font-weight:600;}QPushButton:hover{background:#D7D7D7;}"

class StudioSettingsDialog(QDialog):
    def __init__(self, repo: Repo, license_manager: LicenseManager, backup_service: BackupService | None = None, parent=None):
        super().__init__(parent)
        self.repo = repo
        self.license_manager = license_manager
        self.backup_service = backup_service
        self.setWindowTitle("Налаштування студії")
        self.resize(900, 680)
        self._build_ui()
        self._load()

    def _build_ui(self) -> None:
        root = QVBoxLayout(self)
        root.setContentsMargins(16, 16, 16, 16)
        root.setSpacing(12)
        title = QLabel("Налаштування студії")
        title.setStyleSheet("font-size: 12pt; font-weight: 700;")
        root.addWidget(title)
        self.tabs = QTabWidget()
        root.addWidget(self.tabs, 1)

        branding_page = QWidget(); branding_root = QVBoxLayout(branding_page); branding_root.setContentsMargins(8,8,8,8); branding_root.setSpacing(12)
        brand_hint = QLabel("Ці дані використовуються у верхній частині програми: логотип та назва студії.")
        brand_hint.setWordWrap(True); brand_hint.setStyleSheet("color:#4B5563;")
        branding_root.addWidget(brand_hint)
        title_lbl = QLabel("Назва студії"); title_lbl.setStyleSheet("font-weight: 700;")
        branding_root.addWidget(title_lbl)
        self.studio_title_edit = QLineEdit(); self.studio_title_edit.setPlaceholderText("Наприклад: Mi100 Studio Manager")
        branding_root.addWidget(self.studio_title_edit)
        logo_row = QHBoxLayout(); logo_left = QVBoxLayout()
        logo_lbl = QLabel("Лого студії"); logo_lbl.setStyleSheet("font-weight: 700;")
        logo_left.addWidget(logo_lbl); logo_left.addWidget(QLabel("Рекомендовано квадратне зображення."))
        logo_btns = QHBoxLayout(); self.logo_path_edit = QLineEdit(); self.logo_path_edit.setReadOnly(True)
        btn_pick_logo = QPushButton("Завантажити лого"); btn_pick_logo.clicked.connect(self._pick_logo)
        btn_clear_logo = QPushButton("Очистити"); btn_clear_logo.clicked.connect(self._clear_logo)
        logo_btns.addWidget(self.logo_path_edit, 1); logo_btns.addWidget(btn_pick_logo); logo_btns.addWidget(btn_clear_logo)
        logo_left.addLayout(logo_btns); logo_row.addLayout(logo_left,1)
        self.logo_preview = QLabel(); self.logo_preview.setFixedSize(96,96); self.logo_preview.setFrameShape(QFrame.Shape.StyledPanel); self.logo_preview.setAlignment(Qt.AlignmentFlag.AlignCenter)
        logo_row.addWidget(self.logo_preview); branding_root.addLayout(logo_row); branding_root.addStretch(1)
        self.tabs.addTab(branding_page, "Лого та назва")

        requisites_page = QWidget(); req_root = QVBoxLayout(requisites_page); req_root.setContentsMargins(8,8,8,8); req_root.setSpacing(12)
        hint = QLabel("Ці дані використовуються для автоматичного заповнення блоку «Постачальник» у рахунках і актах.")
        hint.setWordWrap(True); hint.setStyleSheet("color:#4B5563;")
        req_root.addWidget(hint)
        req_label = QLabel("Реквізити студії"); req_label.setStyleSheet("font-weight: 700;")
        req_root.addWidget(req_label)
        self.requisites_edit = QTextEdit(); self.requisites_edit.setPlaceholderText("Вкажіть повні реквізити студії для блоку «Постачальник»"); self.requisites_edit.setMinimumHeight(220)
        req_root.addWidget(self.requisites_edit); req_root.addStretch(1)
        self.tabs.addTab(requisites_page, "Реквізити")

        email_page = QWidget(); email_root = QVBoxLayout(email_page); email_root.setContentsMargins(8,8,8,8); email_root.setSpacing(12)
        email_title = QLabel("SMTP / Email-відправка"); email_title.setStyleSheet("font-size: 12pt; font-weight: 700;")
        email_root.addWidget(email_title)
        email_hint = QLabel("Налаштування використовуються для надсилання рахунків, актів та звітів із програми.")
        email_hint.setWordWrap(True); email_hint.setStyleSheet("color:#4B5563;")
        email_root.addWidget(email_hint)
        smtp_grid = QGridLayout(); smtp_grid.setHorizontalSpacing(14); smtp_grid.setVerticalSpacing(8)
        labels = [("SMTP сервер",0,0),("SMTP пароль / App Password",0,1),("SMTP порт",2,0),("Ім'я відправника",2,1),("SMTP логін",4,0),("Email відправника",4,1)]
        for text,r,c in labels:
            lbl = QLabel(text); lbl.setStyleSheet('font-weight:700;'); smtp_grid.addWidget(lbl,r,c)
        self.smtp_host_edit = QLineEdit(); self.smtp_port_edit = QLineEdit(); self.smtp_port_edit.setPlaceholderText("587 або 465")
        self.smtp_user_edit = QLineEdit(); self.smtp_password_edit = QLineEdit(); self.smtp_password_edit.setEchoMode(QLineEdit.Password)
        self.smtp_sender_name_edit = QLineEdit(); self.smtp_sender_email_edit = QLineEdit()
        smtp_grid.addWidget(self.smtp_host_edit,1,0); smtp_grid.addWidget(self.smtp_password_edit,1,1); smtp_grid.addWidget(self.smtp_port_edit,3,0); smtp_grid.addWidget(self.smtp_sender_name_edit,3,1); smtp_grid.addWidget(self.smtp_user_edit,5,0); smtp_grid.addWidget(self.smtp_sender_email_edit,5,1)
        email_root.addLayout(smtp_grid); email_root.addStretch(1)
        self.tabs.addTab(email_page, "SMTP / Email")

        templates_page = QWidget(); templates_root = QVBoxLayout(templates_page); templates_root.setContentsMargins(8,8,8,8); templates_root.setSpacing(12)
        tmpl_title = QLabel("Шаблони листів"); tmpl_title.setStyleSheet("font-size: 12pt; font-weight: 700;")
        templates_root.addWidget(tmpl_title)
        tmpl_hint = QLabel("Доступні шорткоди: {doc_number}, {recipient_name}. Для документів і звітів доступні мультивалютні шорткоди з контекстного меню редактора шаблону, включно з секціями по валютах і підсумками прописом.")
        tmpl_hint.setWordWrap(True); tmpl_hint.setStyleSheet("color:#4B5563;")
        templates_root.addWidget(tmpl_hint)
        self.templates_tabs = QTabWidget(); self._template_edits = {}
        for key,label in [("client_invoice","Рахунок для замовника"),("client_act","Акт для замовника"),("client_report","Звіт для замовника"),("actor_report","Звіт для підрядника")]:
            page = QWidget(); lay = QVBoxLayout(page); edit = QTextEdit(); lay.addWidget(edit); self._template_edits[key]=edit; self.templates_tabs.addTab(page,label)
        templates_root.addWidget(self.templates_tabs,1)
        self.tabs.addTab(templates_page, "Шаблони листів")

        currencies_page = QWidget(); cur_root = QVBoxLayout(currencies_page); cur_root.setContentsMargins(8,8,8,8); cur_root.setSpacing(10)
        cur_title = QLabel("Валюти"); cur_title.setStyleSheet("font-size: 12pt; font-weight: 700;")
        cur_root.addWidget(cur_title)
        cur_hint = QLabel("Активні валюти доступні для нових проєктів та оплат. Архівні валюти лишаються в історії, але недоступні для нових записів.")
        cur_hint.setWordWrap(True); cur_hint.setStyleSheet("color:#4B5563;")
        cur_root.addWidget(cur_hint)
        self.currencies_table = QTableWidget(0, 4)
        self.currencies_table.setHorizontalHeaderLabels(["Код", "Символ", "Назва", "Статус"])
        self.currencies_table.verticalHeader().setVisible(False)
        self.currencies_table.setEditTriggers(QTableWidget.NoEditTriggers)
        self.currencies_table.horizontalHeader().setSectionResizeMode(0, QHeaderView.ResizeToContents)
        self.currencies_table.horizontalHeader().setSectionResizeMode(1, QHeaderView.ResizeToContents)
        self.currencies_table.horizontalHeader().setSectionResizeMode(2, QHeaderView.Stretch)
        self.currencies_table.horizontalHeader().setSectionResizeMode(3, QHeaderView.ResizeToContents)
        cur_root.addWidget(self.currencies_table, 1)
        self.tabs.addTab(currencies_page, "Валюти")

        backup_page = QWidget(); backup_root = QVBoxLayout(backup_page); backup_root.setContentsMargins(8,8,8,8); backup_root.setSpacing(10)
        btitle = QLabel("Резервні копії / Відновлення / Експорт бази"); btitle.setStyleSheet("font-size: 12pt; font-weight: 700;")
        backup_root.addWidget(btitle)
        folder_row = QHBoxLayout(); self.backup_path_label = QLabel('—'); self.backup_path_label.setStyleSheet("font-weight: 600;")
        self.btn_choose_folder = QPushButton("Обрати папку"); self.btn_choose_folder.setStyleSheet(BTN_GRAY); self.btn_choose_folder.clicked.connect(self._choose_folder)
        folder_row.addWidget(QLabel("Папка резервних копій:")); folder_row.addWidget(self.backup_path_label,1); folder_row.addWidget(self.btn_choose_folder)
        backup_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)
        backup_root.addLayout(options_row)
        actions_row = QHBoxLayout(); self.btn_create_backup = QPushButton("Створити резервну копію"); self.btn_create_backup.setStyleSheet(BTN_GRAY); self.btn_create_backup.clicked.connect(self._create_backup)
        self.btn_export_db = QPushButton("Експорт бази"); self.btn_export_db.setStyleSheet(BTN_GRAY); self.btn_export_db.clicked.connect(self._export_db)
        self.btn_restore_backup = QPushButton("Відновити з резервної копії"); self.btn_restore_backup.setStyleSheet(BTN_GRAY); self.btn_restore_backup.clicked.connect(self._restore_backup)
        self.btn_open_backup_folder = QPushButton("Відкрити папку"); self.btn_open_backup_folder.setStyleSheet(BTN_GRAY); self.btn_open_backup_folder.clicked.connect(self._open_backup_folder)
        for b in (self.btn_create_backup,self.btn_export_db,self.btn_restore_backup,self.btn_open_backup_folder): actions_row.addWidget(b)
        backup_root.addLayout(actions_row)
        subtitle = QLabel("Доступні резервні копії"); subtitle.setStyleSheet("font-weight:700;"); backup_root.addWidget(subtitle)
        self.backup_list = QListWidget(); backup_root.addWidget(self.backup_list,1)
        self.tabs.addTab(backup_page, "Резервні копії")

        license_page = QWidget(); lic_root = QVBoxLayout(license_page); lic_root.setContentsMargins(8,8,8,8); lic_root.setSpacing(12)
        self.license_status_title = QLabel("Ліцензія"); self.license_status_title.setStyleSheet("font-size: 12pt; font-weight: 700;")
        lic_root.addWidget(self.license_status_title)
        self.license_info = QLabel(""); self.license_info.setWordWrap(True); self.license_info.setTextInteractionFlags(Qt.TextSelectableByMouse | Qt.TextSelectableByKeyboard); lic_root.addWidget(self.license_info)
        self.device_code_label = QLabel(""); self.device_code_label.setTextInteractionFlags(Qt.TextSelectableByMouse | Qt.TextSelectableByKeyboard); lic_root.addWidget(self.device_code_label)
        self.license_path_label = QLabel(""); self.license_path_label.setTextInteractionFlags(Qt.TextSelectableByMouse | Qt.TextSelectableByKeyboard); self.license_path_label.setWordWrap(True); lic_root.addWidget(self.license_path_label)
        lic_actions = QHBoxLayout(); b_copy = QPushButton("Скопіювати код пристрою"); b_copy.clicked.connect(lambda: QGuiApplication.clipboard().setText(self.license_manager.device_code)); b_activate = QPushButton("Активувати програму"); b_activate.clicked.connect(self._open_activation); b_refresh = QPushButton("Оновити стан"); b_refresh.clicked.connect(self._load_license_status)
        lic_actions.addWidget(b_copy); lic_actions.addWidget(b_activate); lic_actions.addWidget(b_refresh); lic_actions.addStretch(1); lic_root.addLayout(lic_actions); lic_root.addStretch(1)
        self.tabs.addTab(license_page, "Ліцензія")

        actions = QHBoxLayout(); actions.addStretch(1); cancel_btn = QPushButton("Скасувати"); cancel_btn.clicked.connect(self.reject); actions.addWidget(cancel_btn); save_btn = QPushButton("Зберегти"); save_btn.setObjectName("Primary"); save_btn.clicked.connect(self._save); actions.addWidget(save_btn); root.addLayout(actions)

    def _set_logo_preview(self, path: str) -> None:
        path = (path or "").strip(); self.logo_path_edit.setText(path)
        if path:
            pm = QPixmap(path)
            if not pm.isNull():
                self.logo_preview.setPixmap(pm.scaled(88, 88, Qt.AspectRatioMode.KeepAspectRatio, Qt.TransformationMode.SmoothTransformation)); return
        self.logo_preview.setPixmap(QPixmap()); self.logo_preview.setText("Лого")

    def _pick_logo(self) -> None:
        path, _ = QFileDialog.getOpenFileName(self, "Оберіть лого", "", "Images (*.png *.jpg *.jpeg *.webp *.bmp)")
        if path: self._set_logo_preview(path)

    def _clear_logo(self) -> None:
        self._set_logo_preview("")

    def _load(self) -> None:
        branding = self.repo.get_studio_branding(); self.studio_title_edit.setText(branding.get("studio_title", "Mi100 Studio Manager")); self._set_logo_preview(branding.get("studio_logo_path", ""))
        row = self.repo.get_studio_profile(); self.requisites_edit.setPlainText(str(row["supplier_requisites_text"] or ""))
        email = self.repo.get_email_settings(); self.smtp_host_edit.setText(email.get('smtp_host', '')); self.smtp_port_edit.setText(email.get('smtp_port', '587')); self.smtp_user_edit.setText(email.get('smtp_username', '')); self.smtp_password_edit.setText(email.get('smtp_password', '')); self.smtp_sender_name_edit.setText(email.get('smtp_sender_name', '')); self.smtp_sender_email_edit.setText(email.get('smtp_sender_email', ''))
        for key, edit in self._template_edits.items(): edit.setPlainText(self.repo.get_email_template(key))
        self.currencies_table.setRowCount(0)
        for row in self.repo.get_currencies():
            r = self.currencies_table.rowCount(); self.currencies_table.insertRow(r)
            self.currencies_table.setItem(r, 0, QTableWidgetItem(str(row.get('code') or '')))
            self.currencies_table.setItem(r, 1, QTableWidgetItem(str(row.get('symbol') or '')))
            self.currencies_table.setItem(r, 2, QTableWidgetItem(str(row.get('name') or '')))
            combo = QComboBox(); combo.addItem('Активна', 'active'); combo.addItem('Архівна', 'archived'); combo.addItem('Вимкнена', 'disabled')
            idx = combo.findData(str(row.get('status') or row.get('default_status') or 'disabled'))
            combo.setCurrentIndex(max(0, idx))
            self.currencies_table.setCellWidget(r, 3, combo)
        self._reload_backups(); self._load_license_status()

    def _load_license_status(self) -> None:
        status = self.license_manager.current_status()
        if status.mode == 'full':
            self.license_info.setText(f"<b>Статус:</b> Активовано<br><b>Тип ліцензії:</b> Повна<br><b>Власник:</b> {status.customer_name or '—'}<br><b>Компанія:</b> {status.company_name or '—'}<br><b>Дата видачі:</b> {status.issued_at or '—'}")
        elif status.mode == 'trial':
            extra = f"<br><b>Попередження:</b> {status.message}" if status.warning_level in ('warning', 'critical') else ''
            self.license_info.setText(f"<b>Статус:</b> Пробна версія<br><b>Тип ліцензії:</b> Trial 60 днів<br><b>Залишилось днів:</b> {status.days_left}<br><b>Дата першого запуску:</b> {status.issued_at or '—'}<br><b>Дата завершення:</b> {status.expires_at or '—'}{extra}")
        else:
            self.license_info.setText(f"<b>Статус:</b> Пробний період завершено або ліцензія неактивна<br><b>Повідомлення:</b> {status.message or '—'}")
        self.device_code_label.setText(f"Код пристрою: {status.device_code}")
        self.license_path_label.setText(f"Шлях до license.dat: {self.license_manager.license_path}")

    def _open_activation(self) -> None:
        dlg = ActivationDialog(self.license_manager, self)
        if dlg.exec() and dlg.activated: self._load_license_status()

    def _save(self) -> None:
        self.repo.save_studio_branding(studio_title=self.studio_title_edit.text().strip(), studio_logo_path=self.logo_path_edit.text().strip())
        self.repo.update_studio_profile(supplier_requisites_text=self.requisites_edit.toPlainText().strip())
        self.repo.save_email_settings(smtp_host=self.smtp_host_edit.text().strip(), smtp_port=self.smtp_port_edit.text().strip(), smtp_username=self.smtp_user_edit.text().strip(), smtp_password=self.smtp_password_edit.text(), smtp_sender_name=self.smtp_sender_name_edit.text().strip(), smtp_sender_email=self.smtp_sender_email_edit.text().strip())
        for key, edit in self._template_edits.items(): self.repo.set_email_template(key, edit.toPlainText().rstrip())
        cur_rows = []
        for r in range(self.currencies_table.rowCount()):
            combo = self.currencies_table.cellWidget(r, 3)
            cur_rows.append({
                'code': self.currencies_table.item(r, 0).text() if self.currencies_table.item(r, 0) else '',
                'status': combo.currentData() if combo is not None else 'disabled',
            })
        requested_disabled = {str(row.get('code') or '').upper(): str(row.get('status') or '') for row in cur_rows if str(row.get('status') or '') == 'disabled'}
        self.repo.save_currencies(cur_rows)
        auto_archived = sorted(code for code in requested_disabled if code in self.repo.get_used_currency_codes())
        if auto_archived:
            QMessageBox.information(self, 'Валюти', 'Валюти, які вже використовуються в проєктах, оплатах або документах, не можуть бути повністю вимкнені. Для них автоматично встановлено статус «Архівна»:\n' + ', '.join(auto_archived))
        self.accept()

    def _reload_backups(self) -> None:
        self.backup_list.clear()
        if not self.backup_service:
            self.backup_path_label.setText('—')
            for w in (self.btn_choose_folder, self.btn_create_backup, self.btn_export_db, self.btn_restore_backup, self.btn_open_backup_folder): w.setEnabled(False)
            return
        self.backup_path_label.setText(str(self.backup_service.get_backup_dir()))
        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):
        item = self.backup_list.currentItem()
        return None if item is None else item.data(Qt.UserRole)

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

    def _create_backup(self):
        if not self.backup_service: return
        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_backups()
        QMessageBox.information(self, "Резервна копія", f"Резервну копію створено:\n{path}")

    def _export_db(self):
        if not self.backup_service: return
        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(filename)
        except Exception as exc:
            QMessageBox.critical(self, "Експорт бази", f"Не вдалося експортувати базу:\n{exc}")
            return
        QMessageBox.information(self, "Експорт бази", f"Базу даних експортовано:\n{path}")

    def _restore_backup(self):
        if not self.backup_service: return
        path = self._selected_backup_path()
        if path is None:
            path, _ = QFileDialog.getOpenFileName(self, "Оберіть резервну копію", str(self.backup_service.get_backup_dir()), "ZIP архів (*.zip)")
            if not path: return
        ask = QMessageBox.question(self, "Відновлення", "Програма відновить дані з резервної копії. Після відновлення програму потрібно буде закрити й запустити знову. Продовжити?", QMessageBox.Yes | QMessageBox.No, QMessageBox.No)
        if ask != QMessageBox.Yes: return
        try: self.backup_service.restore_from_backup(path)
        except Exception as exc:
            QMessageBox.critical(self, "Відновлення", f"Не вдалося відновити резервну копію:\n{exc}")
            return
        QMessageBox.information(self, "Відновлення завершено", "Дані відновлено. Програму потрібно запустити знову.")
        self.accept()

    def _open_backup_folder(self):
        if self.backup_service: QDesktopServices.openUrl(QUrl.fromLocalFile(str(self.backup_service.get_backup_dir())))
