"""Export management module for SecInterp main dialog.

This module handles exporting preview data to various file formats
(PNG, PDF, SVG) and orchestrating data exports (SHP, CSV) via ExportService.
"""

from __future__ import annotations

from pathlib import Path
from typing import TYPE_CHECKING

from qgis.core import Qgis, QgsSettings
from qgis.PyQt.QtCore import QSize
from qgis.PyQt.QtGui import QColor
from qgis.PyQt.QtWidgets import QFileDialog

import sec_interp
from sec_interp.core.exceptions import SecInterpError
from sec_interp.core.performance_metrics import MetricsCollector, PerformanceTimer
from sec_interp.core.services.export_service import ExportService
from sec_interp.exporters import get_exporter
from sec_interp.logger_config import get_logger

if TYPE_CHECKING:
    pass

logger = get_logger(__name__)


class ExportManager:
    """Manages all export operations for the dialog.

    This class handles exporting preview data to various file formats
    (PNG, PDF, SVG) and orchestrating data exports (SHP, CSV) via ExportService.
    """

    def __init__(self, dialog: sec_interp.gui.main_dialog.SecInterpDialog) -> None:
        """Initialize export manager with reference to parent dialog.

        Args:
            dialog: The :class:`sec_interp.gui.main_dialog.SecInterpDialog` instance

        """
        self.dialog = dialog
        self.metrics = MetricsCollector()
        self.export_service = ExportService(self.dialog.plugin_instance.controller)

    def export_preview(self) -> bool:
        """Export the current preview to a file."""
        self.metrics.clear()
        try:
            if not self.dialog.current_canvas:
                self._show_export_error(
                    self.dialog.tr("No preview available to export. Generate a preview first.")
                )
                return False

            layers = self.dialog.current_canvas.layers()
            if not layers:
                self._show_export_error(self.dialog.tr("No layers to export."))
                return False

            output_path = self._get_save_path()
            if not output_path:
                return False

            with PerformanceTimer("Total Preview Export Time", self.metrics):
                success = self._execute_preview_export(output_path, layers)
                if success:
                    self.dialog.push_message(
                        self.dialog.tr("Success"),
                        self.dialog.tr("Preview exported to {}").format(output_path.name),
                        level=Qgis.Success,
                    )
                return success

        except Exception as e:
            self.dialog.handle_error(e, "Export Error")
            return False

    def _show_export_error(self, message: str) -> None:
        """Show a standardization export error message."""
        self.dialog.push_message(self.dialog.tr("Export Error"), message, level=Qgis.Warning)

    def _get_save_path(self) -> Path | None:
        """Prompt user for save location and update settings."""
        settings = QgsSettings()
        last_dir = settings.value("SecInterp/lastExportDir", "", type=str)
        default_path = str(Path(last_dir) / "preview.png") if last_dir else "preview.png"

        file_filter = (
            "PNG Image (*.png);;JPEG Image (*.jpg *.jpeg);;PDF Document (*.pdf);;SVG Vector (*.svg)"
        )

        path_str, _ = QFileDialog.getSaveFileName(
            self.dialog, "Export Preview", default_path, file_filter
        )
        if not path_str:
            return None

        path = Path(path_str)
        settings.setValue("SecInterp/lastExportDir", str(path.parent))
        return path

    def _execute_preview_export(self, path: Path, layers: list) -> bool:
        """Execute the export logic internally."""
        ext = path.suffix.lower()
        width, height, dpi = self._get_export_dimensions(ext)

        opts = self.dialog.get_preview_options()
        export_params = {
            "width": width,
            "height": height,
            "dpi": dpi,
            "background_color": QColor(255, 255, 255),
            "show_legend": opts.get("show_legend", True),
            "legend_renderer": getattr(self.dialog.plugin_instance, "preview_renderer", None),
            "title": self.dialog.tr("Section Interpretation Preview"),
            "description": self.dialog.tr("Generated by SecInterp QGIS Plugin"),
            "extent": self.dialog.current_canvas.extent(),
        }

        map_settings = self.export_service.get_map_settings(
            layers,
            export_params["extent"],
            self.dialog.preview_widget.canvas.size(),
            export_params["background_color"],
        )

        if ext in [".png", ".jpg", ".jpeg"]:
            map_settings.setOutputSize(QSize(width, height))

        exporter = get_exporter(ext, export_params)
        return exporter.export(path, map_settings)

    def _get_export_dimensions(self, ext: str) -> tuple[int, int, int]:
        """Calculate export dimensions and resolution."""
        canvas_width = self.dialog.preview_widget.canvas.width()
        canvas_height = self.dialog.preview_widget.canvas.height()

        if ext in [".png", ".jpg", ".jpeg"]:
            return canvas_width * 3, canvas_height * 3, 300
        return canvas_width, canvas_height, 96

    def export_data(self) -> bool:
        """Orchestrate full data export (SHP/CSV) to the selected folder.

        Returns:
            True if successful, False otherwise

        """
        try:
            # 1. Validate inputs via dialog
            params = self.dialog.plugin_instance._get_and_validate_inputs()
            if not params:
                return False

            # Auto-save current valid settings
            self.dialog.state_manager.save_settings()

            # Get values for output path (still needed from dialog/values)
            values = self.dialog.get_selected_values()
            output_folder = Path(values["output_path"])

            # 2. Generate data via controller
            self.dialog.preview_widget.results_text.setPlainText(
                self.dialog.tr("✓ Generating data for export...")
            )
            profile_data, geol_data, struct_data, drillhole_data, _ = (
                self.dialog.plugin_instance.controller.generate_profile_data(params)
            )

            if not profile_data:
                self.dialog.push_message(
                    self.dialog.tr("Error"),
                    self.dialog.tr("No profile data generated."),
                    level=Qgis.Critical,
                )
                return False

            num_interps = len(self.dialog.interpretations)
            logger.info(f"Exporting data: found {num_interps} interpretation(s) in dialog.")

            # Extract export settings
            export_options = {
                "exp_topo": values.get("exp_topo", True),
                "exp_geol": values.get("exp_geol", True),
                "exp_struct": values.get("exp_struct", True),
                "exp_drill": values.get("exp_drill", True),
                "exp_interp": values.get("exp_interp", True),
                "drill_3d_traces": values.get("drill_3d_traces", True),
                "drill_3d_intervals": values.get("drill_3d_intervals", True),
                "drill_3d_original": values.get("drill_3d_original", True),
                "drill_3d_projected": values.get("drill_3d_projected", False),
            }

            result_msg = self.export_service.export_data(
                output_folder,
                params,
                profile_data,
                geol_data,
                struct_data,
                drillhole_data,
                interp_data=self.dialog.interpretations,
                export_options=export_options,
            )

            self.dialog.preview_widget.results_text.setPlainText("\n".join(result_msg))
        except SecInterpError as e:
            self.dialog.handle_error(e, "Data Export Error")
            return False
        except Exception as e:
            self.dialog.handle_error(e, "Unexpected Data Export Error")
            return False
        else:
            return True
