# Copyright (c) 2021, 2026, Oracle and/or its affiliates.
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License, version 2.0,
# as published by the Free Software Foundation.
#
# This program is designed to work with certain software (including
# but not limited to OpenSSL) that is licensed under separate terms, as
# designated in a particular file or component or in included license
# documentation.  The authors of MySQL hereby grant you an additional
# permission to link the program and your derivative works with the
# separately licensed software that they have either included with
# the program or referenced in the documentation.
#
# 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, version 2.0, for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software Foundation, Inc.,
# 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA

import threading

import gui_plugin.core.Context as context
import gui_plugin.core.Logger as logger


class BaseTask:
    def __init__(
        self,
        task_id=None,
        result_queue=None,
        result_callback=None,
        options=None,
        skip_completion=False,
    ):
        self.thread_id = threading.current_thread().native_id
        self.task_id = task_id
        self.result_queue = result_queue
        self.result_callback = result_callback
        self.options = options if options else {}
        self.cancelled = False
        self.completion_event = (
            None if skip_completion else context.set_completion_event()
        )

    def dispatch_result(self, state, message=None, data=None):
        if self.result_queue is not None:
            if message is not None:
                self.result_queue.put(message)

            if data is not None:
                self.result_queue.put(data)

        if self.completion_event is not None and state in ["ERROR", "CANCELLED"]:
            if state == "ERROR":
                self.completion_event.add_error(Exception(message))
            if state == "CANCELLED":
                self.completion_event.set_cancelled()
        elif self.result_callback is not None:
            try:
                self.result_callback(state, message, self.task_id, data)
            except Exception as e:
                logger.debug(self.result_callback)
                logger.exception(
                    e, "There was an unhandled exception during the callback"
                )
                raise

    def do_execute(self):
        raise NotImplementedError()

    def cancel(self):
        self.cancelled = True

    def execute(self):
        try:
            (
                self.do_execute()
                if not self.cancelled
                else self.dispatch_result("CANCELLED")
            )
        finally:
            if self.completion_event:
                self.completion_event.set()


class CommandTask(BaseTask):
    def __init__(
        self,
        task_id,
        command,
        params=None,
        result_queue=None,
        result_callback=None,
        options=None,
        skip_completion=False,
    ):
        super().__init__(
            task_id,
            result_queue,
            result_callback,
            options,
            skip_completion=skip_completion,
        )
        self.command = command
        self.params = params
