# Copyright: Ankitects Pty Ltd and contributors
# License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html

from __future__ import annotations

from collections.abc import Sequence

import aqt
import aqt.forms
import aqt.operations
from anki.notes import NoteId
from aqt import AnkiQt
from aqt.operations import QueryOp
from aqt.operations.note import find_and_replace
from aqt.operations.tag import find_and_replace_tag
from aqt.qt import *
from aqt.utils import (
    HelpPage,
    disable_help_button,
    openHelp,
    qconnect,
    restore_combo_history,
    restore_combo_index_for_session,
    restore_is_checked,
    restoreGeom,
    save_combo_history,
    save_combo_index_for_session,
    save_is_checked,
    saveGeom,
    tooltip,
    tr,
)


class FindAndReplaceDialog(QDialog):
    COMBO_NAME = "BrowserFindAndReplace"

    def __init__(
        self,
        parent: QWidget,
        *,
        mw: AnkiQt,
        note_ids: Sequence[NoteId],
        field: str | None = None,
    ) -> None:
        """
        If 'field' is passed, only this is added to the field selector.
        Otherwise, the fields belonging to the 'note_ids' are added.
        """
        super().__init__(parent)
        self.mw = mw
        self.note_ids = note_ids
        self.field_names: list[str] = []
        self._field = field

        if field:
            self._show([field])
        elif note_ids:
            # fetch field names and then show
            QueryOp(
                parent=mw,
                op=lambda col: col.field_names_for_note_ids(note_ids),
                success=self._show,
            ).run_in_background()
        else:
            self._show([])

    def _show(self, field_names: Sequence[str]) -> None:
        # add "all fields" and "tags" to the top of the list
        self.field_names = [
            tr.browsing_all_fields(),
            tr.editing_tags(),
        ] + list(field_names)

        disable_help_button(self)
        self.form = aqt.forms.findreplace.Ui_Dialog()
        self.form.setupUi(self)
        self.setWindowModality(Qt.WindowModality.WindowModal)

        self._find_history = restore_combo_history(
            self.form.find, self.COMBO_NAME + "Find"
        )

        find_completer = self.form.find.completer()
        assert find_completer is not None
        find_completer.setCaseSensitivity(Qt.CaseSensitivity.CaseSensitive)
        self._replace_history = restore_combo_history(
            self.form.replace, self.COMBO_NAME + "Replace"
        )
        replace_completer = self.form.replace.completer()
        assert replace_completer is not None
        replace_completer.setCaseSensitivity(Qt.CaseSensitivity.CaseSensitive)

        if not self.note_ids:
            # no selected notes to affect
            self.form.selected_notes.setChecked(False)
            self.form.selected_notes.setEnabled(False)
        elif self._field:
            self.form.selected_notes.setChecked(False)

        restore_is_checked(self.form.re, self.COMBO_NAME + "Regex")
        restore_is_checked(self.form.ignoreCase, self.COMBO_NAME + "ignoreCase")

        self.form.field.addItems(self.field_names)
        if self._field:
            self.form.field.setCurrentIndex(self.field_names.index(self._field))
        else:
            restore_combo_index_for_session(
                self.form.field, self.field_names, self.COMBO_NAME + "Field"
            )

        qconnect(self.form.buttonBox.helpRequested, self.show_help)

        restoreGeom(self, "findreplace")
        self.show()
        self.form.find.setFocus()

    def accept(self) -> None:
        saveGeom(self, "findreplace")
        save_combo_index_for_session(self.form.field, self.COMBO_NAME + "Field")

        search = save_combo_history(
            self.form.find, self._find_history, self.COMBO_NAME + "Find"
        )
        replace = save_combo_history(
            self.form.replace, self._replace_history, self.COMBO_NAME + "Replace"
        )
        regex = self.form.re.isChecked()
        match_case = not self.form.ignoreCase.isChecked()
        save_is_checked(self.form.re, self.COMBO_NAME + "Regex")
        save_is_checked(self.form.ignoreCase, self.COMBO_NAME + "ignoreCase")

        if not self.form.selected_notes.isChecked():
            # an empty list means *all* notes
            self.note_ids = []

        parent_widget = self.parentWidget()
        assert parent_widget is not None

        # tags?
        if self.form.field.currentIndex() == 1:
            op = find_and_replace_tag(
                parent=parent_widget,
                note_ids=self.note_ids,
                search=search,
                replacement=replace,
                regex=regex,
                match_case=match_case,
            )
        else:
            # fields
            if self.form.field.currentIndex() == 0:
                field = None
            else:
                field = self.field_names[self.form.field.currentIndex()]

            op = find_and_replace(
                parent=parent_widget,
                note_ids=self.note_ids,
                search=search,
                replacement=replace,
                regex=regex,
                field_name=field,
                match_case=match_case,
            )

        if not self.note_ids:
            op.success(
                lambda out: tooltip(
                    tr.browsing_notes_updated(count=out.count),
                    parent=self.parentWidget(),
                )
            )
        op.run_in_background()

        super().accept()

    def show_help(self) -> None:
        openHelp(HelpPage.BROWSING_FIND_AND_REPLACE)
