# radar_data_reader/core/process_runner.py

"""
A dedicated, reusable utility for running external command-line processes.
This module encapsulates the logic for subprocess creation, real-time output
streaming, and robust error handling, inspired by a previously successful
implementation for g_reconvert.exe.
"""

import subprocess
import os
import queue
from typing import List, Dict, Any, Optional

from ..utils import logger

log = logger.get_logger(__name__)


class ProcessRunner:
    """
    Executes an external command, captures its output in real-time,
    and reports status through a queue.
    """

    def __init__(
        self,
        command_list: List[str],
        result_queue: queue.Queue,
        working_dir: Optional[str] = None,
    ):
        """
        Initializes the runner.

        Args:
            command_list: The command and its arguments as a list of strings.
            result_queue: A queue to send status updates and output to.
            working_dir: The directory where the command should be executed.
        """
        self.command_list = command_list
        self.result_queue = result_queue
        self.working_dir = working_dir
        self.return_code: Optional[int] = None

    def run(self) -> int:
        """
        Executes the command and blocks until it completes.

        Returns:
            The final return code of the process.
        """
        process = None
        try:
            exe_path = self.command_list[0]
            if not os.path.exists(exe_path):
                self._send_error(f"Executable not found or invalid path: '{exe_path}'")
                return -1

            if self.working_dir and not os.path.isdir(self.working_dir):
                self._send_error(
                    f"Working directory does not exist: '{self.working_dir}'"
                )
                return -1

            log.info(f"Starting process: {' '.join(self.command_list)}")
            log.info(f"Working directory: {self.working_dir or os.getcwd()}")

            creationflags = subprocess.CREATE_NO_WINDOW if os.name == "nt" else 0

            process = subprocess.Popen(
                self.command_list,
                stdout=subprocess.PIPE,
                stderr=subprocess.STDOUT,
                text=True,
                encoding="utf-8",
                errors="replace",
                bufsize=1,
                creationflags=creationflags,
                cwd=self.working_dir,
            )

            if process.stdout:
                for line in iter(process.stdout.readline, ""):
                    self._send_log(line.strip())

            self.return_code = process.wait()
            log.info(f"Process finished with return code: {self.return_code}")
            return self.return_code

        except FileNotFoundError:
            self._send_error(f"Executable not found: {self.command_list[0]}")
            self.return_code = -1
        except PermissionError:
            self._send_error(f"Permission denied to execute: {self.command_list[0]}")
            self.return_code = -1
        except Exception as e:
            error_msg = f"An unexpected error occurred during execution: {e}"
            log.error(error_msg, exc_info=True)
            self._send_error(error_msg)
            self.return_code = -1

        return self.return_code if self.return_code is not None else -1

    def _send_log(self, message: str):
        """Sends a log message to the result queue."""
        self.result_queue.put({"type": "process_log", "message": message})

    def _send_error(self, message: str):
        """Sends an error message to the result queue and logs it."""
        log.error(message)
        self.result_queue.put({"type": "process_error", "message": message})
