"""
Rule configuration widgets: each rule type has a small form that updates the Rule model.
"""
from PyQt6.QtWidgets import (
    QWidget,
    QVBoxLayout,
    QHBoxLayout,
    QLabel,
    QLineEdit,
    QSpinBox,
    QComboBox,
    QCheckBox,
    QGroupBox,
    QFormLayout,
    QStackedWidget,
    QPushButton,
    QFileDialog,
)
from PyQt6.QtCore import pyqtSignal

from engine.rules import (
    ReplaceRule,
    InsertRule,
    RemoveRule,
    CaseRule,
    NumberingRule,
    EpisodeRenumberRule,
    RegexRule,
    PrefixSuffixRule,
    CsvMappingRule,
)


class ReplaceRuleWidget(QWidget):
    ruleChanged = pyqtSignal()

    def __init__(self, parent=None):
        super().__init__(parent)
        layout = QFormLayout(self)
        self.enabled_cb = QCheckBox("Use this rule")
        self.enabled_cb.setChecked(False)
        self.enabled_cb.toggled.connect(self._emit)
        layout.addRow(self.enabled_cb)
        self.find = QLineEdit()
        self.find.setPlaceholderText("Text to find")
        self.find.textChanged.connect(self._emit)
        self.replace = QLineEdit()
        self.replace.setPlaceholderText("Replace with")
        self.replace.textChanged.connect(self._emit)
        self.caseSensitive = QCheckBox("Case sensitive")
        self.caseSensitive.toggled.connect(self._emit)
        self.wholeWord = QCheckBox("Whole word only")
        self.wholeWord.toggled.connect(self._emit)
        layout.addRow("Find:", self.find)
        layout.addRow("Replace with:", self.replace)
        layout.addRow(self.caseSensitive)
        layout.addRow(self.wholeWord)

    def _emit(self):
        self.ruleChanged.emit()

    def getRule(self) -> ReplaceRule:
        r = ReplaceRule(
            find=self.find.text(),
            replace=self.replace.text(),
            case_sensitive=self.caseSensitive.isChecked(),
            whole_word=self.wholeWord.isChecked(),
        )
        r.enabled = self.enabled_cb.isChecked()
        return r


class RegexRuleWidget(QWidget):
    ruleChanged = pyqtSignal()

    def __init__(self, parent=None):
        super().__init__(parent)
        layout = QFormLayout(self)
        self.enabled_cb = QCheckBox("Use this rule")
        self.enabled_cb.setChecked(False)
        self.enabled_cb.toggled.connect(self._emit)
        layout.addRow(self.enabled_cb)
        self.pattern = QLineEdit()
        self.pattern.setPlaceholderText(r"e.g. S(\d+)E(\d+)")
        self.pattern.textChanged.connect(self._emit)
        self.replacement = QLineEdit()
        self.replacement.setPlaceholderText(r"e.g. S\1E\2")
        self.replacement.textChanged.connect(self._emit)
        layout.addRow("Regex pattern:", self.pattern)
        layout.addRow("Replacement:", self.replacement)

    def _emit(self):
        self.ruleChanged.emit()

    def getRule(self) -> RegexRule:
        r = RegexRule(pattern=self.pattern.text(), replacement=self.replacement.text())
        r.enabled = self.enabled_cb.isChecked()
        return r


class InsertRuleWidget(QWidget):
    ruleChanged = pyqtSignal()

    def __init__(self, parent=None):
        super().__init__(parent)
        layout = QFormLayout(self)
        self.enabled_cb = QCheckBox("Use this rule")
        self.enabled_cb.setChecked(False)
        self.enabled_cb.toggled.connect(self._emit)
        layout.addRow(self.enabled_cb)
        self.text = QLineEdit()
        self.text.setPlaceholderText("Text to insert")
        self.text.textChanged.connect(self._emit)
        self.position = QComboBox()
        self.position.addItems(["At start", "At end", "At position..."])
        self.position.setCurrentIndex(0)
        self.position.currentIndexChanged.connect(self._emit)
        self.positionSpin = QSpinBox()
        self.positionSpin.setMinimum(0)
        self.positionSpin.setMaximum(9999)
        self.positionSpin.valueChanged.connect(self._emit)
        layout.addRow("Text:", self.text)
        layout.addRow("Position:", self.position)
        layout.addRow("Index:", self.positionSpin)

    def _emit(self):
        self.ruleChanged.emit()

    def getRule(self) -> InsertRule:
        idx = self.position.currentIndex()
        if idx == 0:
            pos = 0
        elif idx == 1:
            pos = -1
        else:
            pos = self.positionSpin.value()
        r = InsertRule(text=self.text.text(), position=pos)
        r.enabled = self.enabled_cb.isChecked()
        return r


class RemoveRuleWidget(QWidget):
    ruleChanged = pyqtSignal()

    def __init__(self, parent=None):
        super().__init__(parent)
        layout = QFormLayout(self)
        self.enabled_cb = QCheckBox("Use this rule")
        self.enabled_cb.setChecked(False)
        self.enabled_cb.toggled.connect(self._emit)
        layout.addRow(self.enabled_cb)
        self.removeType = QComboBox()
        self.removeType.addItems([
            "Remove text",
            "Remove all digits",
            "Remove first N characters",
            "Remove last N characters",
        ])
        self.removeType.currentIndexChanged.connect(self._emit)
        self.value = QLineEdit()
        self.value.setPlaceholderText("Text or number")
        self.value.textChanged.connect(self._emit)
        layout.addRow("Type:", self.removeType)
        layout.addRow("Value:", self.value)

    def _emit(self):
        self.ruleChanged.emit()

    def getRule(self) -> RemoveRule:
        idx = self.removeType.currentIndex()
        types = ["chars", "digits", "first_n", "last_n"]
        r = RemoveRule(remove_type=types[idx], value=self.value.text())
        r.enabled = self.enabled_cb.isChecked()
        return r


class CaseRuleWidget(QWidget):
    ruleChanged = pyqtSignal()

    def __init__(self, parent=None):
        super().__init__(parent)
        layout = QFormLayout(self)
        self.enabled_cb = QCheckBox("Use this rule")
        self.enabled_cb.setChecked(False)
        self.enabled_cb.toggled.connect(self._emit)
        layout.addRow(self.enabled_cb)
        self.caseType = QComboBox()
        self.caseType.addItems(["Title Case", "UPPER", "lower", "Sentence case"])
        self.caseType.currentIndexChanged.connect(self._emit)
        layout.addRow("Case:", self.caseType)

    def _emit(self):
        self.ruleChanged.emit()

    def getRule(self) -> CaseRule:
        types = ["title", "upper", "lower", "sentence"]
        r = CaseRule(case_type=types[self.caseType.currentIndex()])
        r.enabled = self.enabled_cb.isChecked()
        return r


class NumberingRuleWidget(QWidget):
    ruleChanged = pyqtSignal()

    def __init__(self, parent=None):
        super().__init__(parent)
        layout = QFormLayout(self)
        self.enabled_cb = QCheckBox("Use this rule")
        self.enabled_cb.setChecked(False)
        self.enabled_cb.toggled.connect(self._emit)
        layout.addRow(self.enabled_cb)
        self.start = QSpinBox()
        self.start.setMinimum(-9999)
        self.start.setMaximum(99999)
        self.start.setValue(1)
        self.start.valueChanged.connect(self._emit)
        self.step = QSpinBox()
        self.step.setMinimum(1)
        self.step.setMaximum(100)
        self.step.setValue(1)
        self.step.valueChanged.connect(self._emit)
        self.padding = QSpinBox()
        self.padding.setMinimum(1)
        self.padding.setMaximum(10)
        self.padding.setValue(2)
        self.padding.valueChanged.connect(self._emit)
        self.where = QComboBox()
        self.where.addItems(["Prefix", "Suffix", "Insert at index"])
        self.where.currentIndexChanged.connect(self._emit)
        self.separator = QLineEdit()
        self.separator.setText(" ")
        self.separator.textChanged.connect(self._emit)
        self.insertAt = QSpinBox()
        self.insertAt.setMinimum(0)
        self.insertAt.setMaximum(9999)
        self.insertAt.valueChanged.connect(self._emit)
        layout.addRow("Start:", self.start)
        layout.addRow("Step:", self.step)
        layout.addRow("Padding:", self.padding)
        layout.addRow("Where:", self.where)
        layout.addRow("Separator:", self.separator)
        layout.addRow("Insert at index:", self.insertAt)

    def _emit(self):
        self.ruleChanged.emit()

    def getRule(self) -> NumberingRule:
        where_map = ["prefix", "suffix", "insert_at"]
        r = NumberingRule(
            start=self.start.value(),
            step=self.step.value(),
            padding=self.padding.value(),
            where=where_map[self.where.currentIndex()],
            insert_at=self.insertAt.value(),
            separator=self.separator.text() or " ",
        )
        r.enabled = self.enabled_cb.isChecked()
        return r


class EpisodeRenumberRuleWidget(QWidget):
    ruleChanged = pyqtSignal()

    def __init__(self, parent=None):
        super().__init__(parent)
        layout = QFormLayout(self)
        self.enabled_cb = QCheckBox("Use this rule")
        self.enabled_cb.setChecked(False)
        self.enabled_cb.toggled.connect(self._emit)
        layout.addRow(self.enabled_cb)
        self.start = QSpinBox()
        self.start.setMinimum(1)
        self.start.setMaximum(9999)
        self.start.setValue(1)
        self.start.valueChanged.connect(self._emit)
        self.step = QSpinBox()
        self.step.setMinimum(1)
        self.step.setValue(1)
        self.step.valueChanged.connect(self._emit)
        self.padding = QSpinBox()
        self.padding.setMinimum(1)
        self.padding.setMaximum(3)
        self.padding.setValue(2)
        self.padding.valueChanged.connect(self._emit)
        layout.addRow("First episode number:", self.start)
        layout.addRow("Step:", self.step)
        layout.addRow("Zero-pad width:", self.padding)
        info = QLabel(
            "Matches S01E05 - Title (single) or S01E05-E06 - Title (two-part). "
            "Ranges keep their length: S01E01-E02, S01E03-E04, … Order follows the file list / table sort."
        )
        info.setWordWrap(True)
        layout.addRow(info)

    def _emit(self):
        self.ruleChanged.emit()

    def getRule(self) -> EpisodeRenumberRule:
        r = EpisodeRenumberRule(
            start=self.start.value(),
            step=self.step.value(),
            padding=self.padding.value(),
        )
        r.enabled = self.enabled_cb.isChecked()
        return r


class PrefixSuffixRuleWidget(QWidget):
    ruleChanged = pyqtSignal()

    def __init__(self, parent=None):
        super().__init__(parent)
        layout = QFormLayout(self)
        self.enabled_cb = QCheckBox("Use this rule")
        self.enabled_cb.setChecked(False)
        self.enabled_cb.toggled.connect(self._emit)
        layout.addRow(self.enabled_cb)
        self.prefix = QLineEdit()
        self.prefix.setPlaceholderText("Prefix")
        self.prefix.textChanged.connect(self._emit)
        self.suffix = QLineEdit()
        self.suffix.setPlaceholderText("Suffix")
        self.suffix.textChanged.connect(self._emit)
        layout.addRow("Prefix:", self.prefix)
        layout.addRow("Suffix:", self.suffix)

    def _emit(self):
        self.ruleChanged.emit()

    def getRule(self) -> PrefixSuffixRule:
        r = PrefixSuffixRule(prefix=self.prefix.text(), suffix=self.suffix.text())
        r.enabled = self.enabled_cb.isChecked()
        return r


class CsvMappingRuleWidget(QWidget):
    ruleChanged = pyqtSignal()

    def __init__(self, parent=None):
        super().__init__(parent)
        layout = QFormLayout(self)
        self.enabled_cb = QCheckBox("Use this rule")
        self.enabled_cb.setChecked(False)
        self.enabled_cb.toggled.connect(self._emit)
        layout.addRow(self.enabled_cb)
        path_row = QHBoxLayout()
        self.path_edit = QLineEdit()
        self.path_edit.setPlaceholderText("Path to CSV file…")
        self.path_edit.textChanged.connect(self._emit)
        browse_btn = QPushButton("Browse…")
        browse_btn.clicked.connect(self._browse)
        path_row.addWidget(self.path_edit, 1)
        path_row.addWidget(browse_btn)
        layout.addRow("CSV file:", path_row)
        info = QLabel('CSV must have columns "Original Name" and "Target Name". Lookup is by current filename.')
        info.setWordWrap(True)
        layout.addRow(info)

    def _browse(self):
        path, _ = QFileDialog.getOpenFileName(
            self,
            "Select CSV",
            "",
            "CSV (*.csv);;All files (*)",
        )
        if path:
            self.path_edit.setText(path)

    def _emit(self):
        self.ruleChanged.emit()

    def getRule(self) -> CsvMappingRule:
        r = CsvMappingRule(csv_path=self.path_edit.text().strip())
        r.enabled = self.enabled_cb.isChecked()
        return r
