# radar_data_reader/core/export_manager.py

import threading
import queue
import subprocess
import re
import shutil
import os
from pathlib import Path
from typing import Dict, Any, List, Optional

from ..utils import logger
from .process_runner import ProcessRunner

log = logger.get_logger(__name__)


class ExportJob:
    """A dataclass-like object to hold all information for a single export job."""

    def __init__(
        self,
        segment_info: Dict[str, Any],
        segment_folder: Path,
        rec_folder: Path,
        export_config: Dict[str, Any],
    ):
        # Inizializzazione robusta tramite dizionario
        self.status: str = str(segment_info.get("Segment (Mode | Scale | WF)", ""))
        self.start_batch: int = int(segment_info.get("Start Batch", 0))
        self.end_batch: int = int(segment_info.get("End Batch", 0))
        self.batch_count: int = int(segment_info.get("Batch Count", 0))
        self.start_file: str = str(segment_info.get("Start File", ""))
        self.end_file: str = str(segment_info.get("End File", ""))

        self.segment_folder = segment_folder
        self.rec_folder = rec_folder
        self.export_config = export_config
        self.cpp_config = export_config.get("g_reconverter_options", {})
        self.report_path = segment_folder / "export_report.txt"


# ... il resto della classe ExportManager rimane invariato ...
# ... Ti fornisco comunque il file completo per sicurezza ...


class ExportManager:
    """
    Manages a queue of export jobs and processes them in a background thread.
    """

    def __init__(self, result_queue: queue.Queue):
        self.job_queue = queue.Queue()
        self.result_queue = result_queue
        self._worker_thread: Optional[threading.Thread] = None
        self._stop_event = threading.Event()

    def start(self):
        if self._worker_thread is not None and self._worker_thread.is_alive():
            log.warning("Export worker thread is already running.")
            return

        self._stop_event.clear()
        self._worker_thread = threading.Thread(target=self._process_jobs, daemon=True)
        self._worker_thread.start()

    def stop(self):
        log.info("Stopping ExportManager worker thread...")
        if self._worker_thread and self._worker_thread.is_alive():
            self.job_queue.put(None)
            self._worker_thread.join(timeout=2.0)
            if self._worker_thread.is_alive():
                log.warning("ExportManager worker thread did not stop in time.")
        else:
            log.info("ExportManager worker thread was not running.")

    def submit_job(self, job: Optional[ExportJob]):
        self.job_queue.put(job)

    def _build_cpp_command(self, job: ExportJob) -> List[str]:
        config = job.cpp_config
        exe_path = config.get("cpp_executable_path")
        if not exe_path or not Path(exe_path).is_file():
            raise ValueError(f"g_reconverter executable not found at: {exe_path}")

        # --- NEW ROBUST LOGIC ---
        # The filename from the summary can be truncated in various ways (.re, or no extension).
        # First, reconstruct the full, correct filename for finding the file on disk.
        start_file_base = job.start_file.split('.')[0]
        start_filename_full = start_file_base + '.rec'
        first_rec_path = job.rec_folder / start_filename_full

        # Second, use a flexible regex to extract the sequence number from the (possibly truncated) name.
        # This regex handles .rec, .re, or no extension.
        start_num_match = re.search(r"_(\d+)(\.re(c?)?)?$", job.start_file)
        end_num_match = re.search(r"_(\d+)(\.re(c?)?)?$", job.end_file)
        # --- END NEW LOGIC ---

        if not start_num_match or not end_num_match:
            log.error(
                f"Could not parse sequence number from filenames: '{job.start_file}', '{job.end_file}'"
            )
            raise ValueError("Could not extract sequence number from REC filenames.")

        start_num, end_num = int(start_num_match.group(1)), int(end_num_match.group(1))
        num_files_to_process = end_num - start_num + 1

        output_basename = job.segment_folder.name
        output_out_path = job.segment_folder / f"{output_basename}.out"
        output_log_path = job.segment_folder / f"{output_basename}.log"

        command = [str(exe_path), str(first_rec_path)]
        base_output_dir_str = str(job.segment_folder)
        if not base_output_dir_str.endswith(os.sep):
            base_output_dir_str += os.sep
        command.append(f"//b={base_output_dir_str}")
        command.append(f"/l={str(output_log_path)}")
        command.append(f"/n={num_files_to_process}")
        if config.get("post_process"):
            command.append(f"/p={config.get('post_process_level', '1')}")
        if config.get("video_show"):
            command.append("/vshow")
        if config.get("video_save"):
            command.append("/vsave")
        if config.get("gps_save_track"):
            command.append("/gps")
        if config.get("no_sign"):
            command.append("/nosign")
        command.append(f"/o={str(output_out_path)}")
        if config.get("silent_overwrite", True):
            command.append("//o")

        return command

    def _process_jobs(self):
        log.info(
            f"ExportManager worker thread started (ID: {threading.get_ident()}). Waiting for jobs."
        )

        while True:
            job = self.job_queue.get()

            if job is None:
                log.info("Poison pill received. All export jobs processed.")
                self.result_queue.put(
                    {"type": "complete", "message": "All segments exported."}
                )
                self.job_queue.task_done()
                break

            log_capture = []
            command_list = []
            return_code = -1

            try:
                log.info(f"Preparing export job for segment: {job.status}")
                if job.segment_folder.exists():
                    shutil.rmtree(job.segment_folder)
                job.segment_folder.mkdir(parents=True)
                command_list = self._build_cpp_command(job)

                local_runner_queue = queue.Queue()
                runner = ProcessRunner(
                    command_list=command_list,
                    result_queue=local_runner_queue,
                    working_dir=str(job.segment_folder),
                )
                return_code = runner.run()

                while not local_runner_queue.empty():
                    try:
                        msg = local_runner_queue.get_nowait()
                        if msg.get("type") == "process_log":
                            log_line = msg["message"]
                            if (
                                "g_reconvert-w" in log_line.lower()
                                and "changed:" in log_line.lower()
                            ):
                                continue
                            log_capture.append(log_line)
                            self.result_queue.put(
                                {"type": "export_log", "message": log_line}
                            )
                        elif msg.get("type") == "process_error":
                            log_capture.append(f"RUNNER ERROR: {msg['message']}")
                            self.result_queue.put(
                                {
                                    "type": "export_log",
                                    "message": f"ERROR: {msg['message']}",
                                }
                            )
                    except queue.Empty:
                        break

            except Exception as e:
                log.error(
                    f"An error occurred in ExportManager job '{job.status}': {e}",
                    exc_info=True,
                )
                log_capture.append(f"\n--- PYTHON EXCEPTION ---\n{str(e)}")
                return_code = -1

            finally:
                is_successful = return_code == 0
                final_status_msg = f"Segment '{job.status}' processing finished. Status: {'SUCCESS' if is_successful else 'FAILED'}, Return Code: {return_code}"
                self.result_queue.put(
                    {"type": "export_log", "message": f"--- {final_status_msg} ---"}
                )

                with open(job.report_path, "w", encoding="utf-8") as f:
                    f.write(f"--- Export Report for Segment ---\n\n")
                    f.write(f"Segment Name: {job.status}\n")
                    f.write(
                        f"Batch Range:  {job.start_batch} - {job.end_batch} ({job.batch_count} batches)\n"
                    )
                    f.write(f"Source Files: From {job.start_file} to {job.end_file}\n")
                    f.write(
                        f"Export Status: {'SUCCESS' if is_successful else 'FAILED'}\n"
                    )
                    f.write(f"Return Code: {return_code}\n\n")
                    if command_list:
                        f.write("--- g_reconverter Command ---\n")
                        f.write(" ".join(map(str, command_list)) + "\n\n")
                    f.write("--- g_reconverter Log ---\n")
                    f.write("\n".join(log_capture))

                log.info(f"Segment report for '{job.status}' written.")
                self.result_queue.put({"type": "segment_progress"})

            self.job_queue.task_done()

        log.info(
            f"ExportManager worker thread finished its work and is terminating (ID: {threading.get_ident()})."
        )
