"""
QThread workers for the GUI.

The GUI is a pure client of the seq_interp service: it does NOT run the
interpreter locally. Interpretation goes through SeqInterpHttpWorker and
artifact export through ArtifactDownloadWorker.
"""
from __future__ import annotations

from PySide6.QtCore import QThread, Signal


class OrchestratorWorker(QThread):
    """
    Generic off-thread caller for client methods.

    Usage:
        worker = OrchestratorWorker(client.run_all, job_id)
        worker.finished.connect(lambda result: ...)
        worker.error.connect(lambda msg: ...)
        worker.start()
    """
    finished = Signal(object)
    error    = Signal(str)
    log_msg  = Signal(str)

    def __init__(self, fn, *args, **kwargs) -> None:
        super().__init__()
        self._fn = fn
        self._args = args
        self._kwargs = kwargs

    def run(self) -> None:
        try:
            result = self._fn(*self._args, **self._kwargs)
            self.finished.emit(result)
        except Exception as exc:
            self.error.emit(f"{type(exc).__name__}: {exc}")


class SeqInterpHttpWorker(QThread):
    """
    Upload a .seq file to the seq_interp service, poll until done,
    and return the full result dict.

    Signals:
        finished(dict)  - interpretation result from GET /result/{task_id}
        error(str)      - error message
        progress(str)   - log / status messages during polling
    """
    finished = Signal(dict)
    error    = Signal(str)
    progress = Signal(str)

    def __init__(self, client, seq_file_path: str,
                 hw_overrides: dict | None = None) -> None:
        """
        client: SeqInterpClient instance
        seq_file_path: local path to the .seq file to upload
        hw_overrides: optional HardwareConstraints overrides applied server-side
        """
        super().__init__()
        self._client = client
        self._seq_file_path = seq_file_path
        self._hw_overrides = hw_overrides or {}

    def run(self) -> None:
        from src.clients.seq_interp_client import SeqInterpError
        try:
            result = self._client.interpret_and_wait(
                self._seq_file_path,
                progress_cb=self.progress.emit,
                hw_overrides=self._hw_overrides,
            )
            self.finished.emit(result)
        except SeqInterpError as exc:
            self.error.emit(f"SeqInterpError: {exc}")
        except Exception as exc:
            self.error.emit(f"{type(exc).__name__}: {exc}")


class ArtifactDownloadWorker(QThread):
    """
    Download a completed task's artifacts zip from the service and extract
    it into dest_dir. Used by the GUI Export action in pure-client mode.

    Signals:
        finished(str)  - destination directory
        error(str)     - error message
        progress(str)  - log messages
    """
    finished = Signal(str)
    error    = Signal(str)
    progress = Signal(str)

    def __init__(self, client, task_id: str, dest_dir: str) -> None:
        super().__init__()
        self._client = client
        self._task_id = task_id
        self._dest_dir = dest_dir

    def run(self) -> None:
        from src.clients.seq_interp_client import SeqInterpError
        try:
            self.progress.emit("Downloading artifacts from service...")
            out = self._client.export_artifacts(self._task_id, self._dest_dir)
            self.finished.emit(out)
        except SeqInterpError as exc:
            self.error.emit(f"SeqInterpError: {exc}")
        except Exception as exc:
            self.error.emit(f"{type(exc).__name__}: {exc}")
