# NextGIS Connect
# Copyright (C) 2026  NextGIS
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or any
# later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License along
# with this program; if not, see <https://www.gnu.org/licenses/>.

from typing import Optional

from qgis.PyQt.QtCore import QSize, Qt, QUrl, pyqtSlot
from qgis.PyQt.QtGui import QDesktopServices
from qgis.PyQt.QtWidgets import QAction, QLineEdit, QWidget

from nextgis_connect.legacy.ngw_connection.application.connections_manager import (
    NgwConnectionsManager,
)
from nextgis_connect.legacy.search.abstract_search_line_edit import (
    AbstractSearchLineEdit,
)
from nextgis_connect.legacy.search.resource_url import SearchResourceUrlParser
from nextgis_connect.legacy.search.search_settings import SearchSettings
from nextgis_connect.legacy.search.text_search_completer_model import (
    TextSearchCompleterModel,
)
from nextgis_connect.platform.qgis.utils import nextgis_domain, utm_tags
from nextgis_connect.ui_kit.icons import qgis_icon
from nextgis_connect.ui_kit.widgets.loading_indicator import (
    LoadingIndicatorIconAnimator,
)


class TextSearchLineEdit(AbstractSearchLineEdit):
    __completer_model: TextSearchCompleterModel

    __loading_action: Optional[QAction]
    __open_help_action: Optional[QAction]
    __loading_icon: LoadingIndicatorIconAnimator

    __connection_id: Optional[str]
    __resource_url_parser: SearchResourceUrlParser

    def __init__(
        self, connection_id: Optional[str], parent: Optional[QWidget] = None
    ) -> None:
        super().__init__(parent)
        self.setPlaceholderText(self.tr("Resource name…"))
        self.setToolTip(
            self.tr(
                "Search by resource name, resource URLs and simple filters"
            )
        )
        self.__connection_id = connection_id
        self.__resource_url_parser = SearchResourceUrlParser()

        # Animation
        self.__loading_action = None
        self.__loading_icon = LoadingIndicatorIconAnimator(
            QSize(16, 16),
            parent=self,
        )
        self.__loading_icon.frame_changed.connect(self.__update_loading_icon)

        # Help action
        self.__open_help_action = None
        self.__change_state_help_action()
        self.textChanged.connect(self.__change_state_help_action)

        # Completer model
        self.__completer_model = TextSearchCompleterModel(connection_id, self)
        self.textEdited.connect(self.__completer_model.set_prefix)
        self.__completer_model.fetching_started.connect(
            self.__show_loading_icon
        )
        self.__completer_model.fetching_finished.connect(
            self.__hide_loading_icon
        )
        self.__completer_model.complete_requested.connect(
            self.__show_completions
        )
        self.search_requested.connect(self.__completer_model.stop_fetching)
        self._completer.setModel(self.__completer_model)

        # Search
        self.search_requested.connect(
            self.update_history,
            Qt.ConnectionType.QueuedConnection,  # type: ignore
        )

    @pyqtSlot(str)
    def set_connection_id(self, connection_id: str) -> None:
        self.__connection_id = connection_id
        self.__completer_model.set_connection_id(connection_id)

    @pyqtSlot()
    def search(self) -> None:
        if not self.isEnabled():
            return

        search_string = self.text()
        if len(search_string) == 0:
            self.reset_requested.emit()
            return

        search_string = search_string.strip()

        settings = SearchSettings()
        settings.add_text_query_to_history(search_string)

        if self.__connection_id is not None:
            connection = NgwConnectionsManager().connection(
                self.__connection_id
            )
            if connection is not None:
                resource_id = self.__resource_url_parser.resource_id(
                    search_string,
                    connection,
                )
                if resource_id is not None:
                    search_string = f"@id = {resource_id}"

        self.search_requested.emit(search_string)

    @pyqtSlot()
    def __show_completions(self) -> None:
        self._completer.setCompletionPrefix("")
        self._completer.complete()

    @pyqtSlot()
    def update_history(self) -> None:
        self.__completer_model.update_history()

    @pyqtSlot()
    def __show_loading_icon(self) -> None:
        if self.__loading_action is not None:
            return

        self.__loading_action = self.addAction(
            self.__loading_icon.current_icon(
                palette=self.palette(),
                device_pixel_ratio=self.devicePixelRatioF(),
            ),
            QLineEdit.ActionPosition.TrailingPosition,
        )
        self.__loading_icon.start()

    @pyqtSlot()
    def __update_loading_icon(self) -> None:
        if self.__loading_action is None:
            return

        self.__loading_action.setIcon(
            self.__loading_icon.current_icon(
                palette=self.palette(),
                device_pixel_ratio=self.devicePixelRatioF(),
            )
        )

    @pyqtSlot()
    def __change_state_help_action(self) -> None:
        if not len(self.text()) and self.__open_help_action is None:
            self.__open_help_action = self.addAction(
                qgis_icon("mActionHelpContents.svg"),
                QLineEdit.ActionPosition.TrailingPosition,
            )
            self.__open_help_action.setToolTip(
                self.tr("Open help in the browser")
            )

            self.__open_help_action.triggered.connect(
                self.__open_help_in_browser
            )

        elif self.__open_help_action is not None:
            self.__open_help_action.deleteLater()
            self.__open_help_action = None

    @pyqtSlot()
    def __open_help_in_browser(self) -> None:
        domain = nextgis_domain("docs")
        utm = utm_tags("search_panel")
        url = f"{domain}/docs_ngconnect/source/filter.html?{utm}"
        QDesktopServices.openUrl(QUrl(url, QUrl.ParsingMode.TolerantMode))

    @pyqtSlot()
    def __hide_loading_icon(self) -> None:
        self.__loading_icon.stop()
        if self.__loading_action is not None:
            self.__loading_action.deleteLater()
            self.__loading_action = None
