from __future__ import annotations

from pathlib import Path

from qtpy.QtCore import QSettings
from qtpy.QtGui import QFont
from qtpy.QtWidgets import (
    QCheckBox,
    QDialog,
    QDialogButtonBox,
    QFileDialog,
    QFormLayout,
    QHBoxLayout,
    QLabel,
    QLineEdit,
    QPushButton,
    QSpinBox,
    QVBoxLayout,
)

from .models import FontSettings


class SettingsDialog(QDialog):
    def __init__(
        self,
        tesseract_path: str,
        language: str,
        dpi: int,
        preprocess: bool,
        parent=None,
    ) -> None:
        super().__init__(parent)

        self.setWindowTitle("OCR Settings")
        self.resize(500, 240)

        self.path_edit = QLineEdit(tesseract_path)
        self.language_edit = QLineEdit(language)

        self.dpi_spin = QSpinBox()
        self.dpi_spin.setRange(72, 600)
        self.dpi_spin.setValue(dpi)

        self.preprocess_check = QCheckBox(
            "Enable grayscale / threshold / denoise preprocessing"
        )
        self.preprocess_check.setChecked(preprocess)

        browse = QPushButton("Browse…")
        browse.clicked.connect(self.browse_tesseract)

        path_layout = QHBoxLayout()
        path_layout.addWidget(self.path_edit)
        path_layout.addWidget(browse)

        form = QFormLayout()
        form.addRow("Tesseract executable:", path_layout)
        form.addRow("OCR language:", self.language_edit)
        form.addRow("Render DPI:", self.dpi_spin)
        form.addRow("", self.preprocess_check)

        buttons = QDialogButtonBox(
            QDialogButtonBox.StandardButton.Ok
            | QDialogButtonBox.StandardButton.Cancel
        )
        buttons.accepted.connect(self.accept)
        buttons.rejected.connect(self.reject)

        layout = QVBoxLayout(self)
        layout.addLayout(form)
        layout.addStretch()
        layout.addWidget(buttons)

    def browse_tesseract(self) -> None:
        path, _ = QFileDialog.getOpenFileName(
            self,
            "Select Tesseract executable",
            str(Path.home()),
            "Executable (*.exe);;All files (*.*)",
        )

        if path:
            self.path_edit.setText(path)

    def values(self) -> tuple[str, str, int, bool]:
        return (
            self.path_edit.text().strip(),
            self.language_edit.text().strip() or "eng",
            self.dpi_spin.value(),
            self.preprocess_check.isChecked(),
        )


class FontDialog(QDialog):
    def __init__(
        self,
        current: FontSettings,
        parent=None,
    ) -> None:
        super().__init__(parent)

        self.setWindowTitle("OCR Font")
        self.resize(420, 180)

        initial_font = QFont(
            current.family,
            int(current.size_pt),
        )
        initial_font.setBold(current.bold)
        initial_font.setItalic(current.italic)
        initial_font.setUnderline(current.underline)

        from qtpy.QtWidgets import QFontDialog

        dialog = QFontDialog(initial_font, self)

        buttons = QDialogButtonBox(
            QDialogButtonBox.StandardButton.Ok
            | QDialogButtonBox.StandardButton.Cancel
        )
        buttons.accepted.connect(self.accept)
        buttons.rejected.connect(self.reject)

        layout = QVBoxLayout(self)
        layout.addWidget(dialog)
        layout.addWidget(buttons)

        self._dialog = dialog

    def selected_font(self) -> FontSettings:
        font = self._dialog.selectedFont()

        return FontSettings(
            family=font.family(),
            size_pt=float(font.pointSizeF()),
            bold=font.bold(),
            italic=font.italic(),
            underline=font.underline(),
        )


class EditTextDialog(QDialog):
    def __init__(
        self,
        text: str,
        parent=None,
    ) -> None:
        super().__init__(parent)

        self.setWindowTitle("Edit OCR Text")
        self.resize(650, 400)

        from qtpy.QtWidgets import QTextEdit

        self.editor = QTextEdit()
        self.editor.setPlainText(text)

        buttons = QDialogButtonBox(
            QDialogButtonBox.StandardButton.Ok
            | QDialogButtonBox.StandardButton.Cancel
        )
        buttons.accepted.connect(self.accept)
        buttons.rejected.connect(self.reject)

        layout = QVBoxLayout(self)
        layout.addWidget(QLabel("Recognized text:"))
        layout.addWidget(self.editor)
        layout.addWidget(buttons)

    def text(self) -> str:
        return self.editor.toPlainText()


def save_qsettings(
    font: FontSettings,
    tesseract_path: str,
    language: str,
    dpi: int,
    preprocess: bool,
) -> None:
    settings = QSettings("Local PDF OCR", "PDFToDOCXOCR")

    settings.setValue("font/family", font.family)
    settings.setValue("font/size", font.size_pt)
    settings.setValue("font/bold", font.bold)
    settings.setValue("font/italic", font.italic)
    settings.setValue("font/underline", font.underline)

    settings.setValue("ocr/tesseract", tesseract_path)
    settings.setValue("ocr/language", language)
    settings.setValue("ocr/dpi", dpi)
    settings.setValue("ocr/preprocess", preprocess)


def load_qsettings() -> tuple[FontSettings, str, str, int, bool]:
    settings = QSettings("Local PDF OCR", "PDFToDOCXOCR")

    font = FontSettings(
        family=str(
            settings.value(
                "font/family",
                "Arial",
            )
        ),
        size_pt=float(
            str(
                settings.value(
                    "font/size",
                    12,
                )
            )
        ),
        bold=bool(
            settings.value(
                "font/bold",
                False,
                type=bool,
            )
        ),
        italic=bool(
            settings.value(
                "font/italic",
                False,
                type=bool,
            )
        ),
        underline=bool(
            settings.value(
                "font/underline",
                False,
                type=bool,
            )
        ),
    )

    path = str(settings.value("ocr/tesseract", ""))
    language = str(settings.value("ocr/language", "eng"))
    dpi = int(str(settings.value("ocr/dpi", 180)))
    preprocess = bool(
        settings.value(
            "ocr/preprocess",
            True,
            type=bool,
        )
    )

    return font, path, language, dpi, preprocess