# -*- coding: utf-8 -*-
"""
Canvas Tools for Advanced Map Downloader

This module provides map tools for canvas interaction:
- Point capture tool for Lat-Long with Pixels mode
- Rectangle drawing tool for extent-based modes
- Rubber band management for visualizing selected areas
"""

from qgis.PyQt.QtCore import Qt, pyqtSignal
from qgis.PyQt.QtGui import QColor
from qgis.gui import QgsMapTool, QgsMapToolEmitPoint, QgsRubberBand
from qgis.core import (
    QgsCoordinateReferenceSystem,
    QgsCoordinateTransform,
    QgsProject,
    QgsPointXY,
    QgsRectangle,
    QgsWkbTypes,
    QgsGeometry
)


class PointCaptureTool(QgsMapToolEmitPoint):
    """
    Map tool for capturing a single point (click on map).
    Used for Lat-Long with Pixels mode where user clicks center point.
    """
    
    point_captured = pyqtSignal(float, float)  # lat, lon in WGS84
    
    def __init__(self, canvas):
        super().__init__(canvas)
        self.canvas = canvas
        self.setCursor(Qt.CrossCursor)
    
    def canvasReleaseEvent(self, event):
        """Handle mouse click to capture point."""
        # Get click point in map coordinates
        point = self.toMapCoordinates(event.pos())
        
        # Get the canvas CRS
        map_crs = self.canvas.mapSettings().destinationCrs()
        wgs84_crs = QgsCoordinateReferenceSystem("EPSG:4326")
        
        # Transform to WGS84 if needed
        if map_crs != wgs84_crs:
            transformer = QgsCoordinateTransform(map_crs, wgs84_crs, QgsProject.instance())
            point_wgs84 = transformer.transform(point)
        else:
            point_wgs84 = point
        
        # Emit the point (lat, lon)
        self.point_captured.emit(point_wgs84.y(), point_wgs84.x())


class RectangleCaptureTool(QgsMapTool):
    """
    Map tool for drawing a rectangle on the canvas.
    Used for XYZ, Square Grid, WKT, WKB, GeoJSON modes.
    """
    
    rectangle_captured = pyqtSignal(float, float, float, float)  # min_lat, min_lon, max_lat, max_lon in WGS84
    
    def __init__(self, canvas):
        super().__init__(canvas)
        self.canvas = canvas
        self.rubber_band = None
        self.start_point = None
        self.end_point = None
        self.is_drawing = False
        self.setCursor(Qt.CrossCursor)
    
    def canvasPressEvent(self, event):
        """Handle mouse press to start drawing."""
        self.start_point = self.toMapCoordinates(event.pos())
        self.end_point = self.start_point
        self.is_drawing = True
        
        # Create rubber band for preview
        if self.rubber_band is None:
            self.rubber_band = QgsRubberBand(self.canvas, QgsWkbTypes.PolygonGeometry)
            self.rubber_band.setColor(QColor(255, 0, 0, 100))
            self.rubber_band.setWidth(2)
        
        self.rubber_band.reset(QgsWkbTypes.PolygonGeometry)
        self._update_rubber_band()
    
    def canvasMoveEvent(self, event):
        """Handle mouse move to update rectangle preview."""
        if not self.is_drawing:
            return
        
        self.end_point = self.toMapCoordinates(event.pos())
        self._update_rubber_band()
    
    def canvasReleaseEvent(self, event):
        """Handle mouse release to finalize rectangle."""
        if not self.is_drawing:
            return
        
        self.end_point = self.toMapCoordinates(event.pos())
        self.is_drawing = False
        
        # Clear the rubber band
        if self.rubber_band:
            self.rubber_band.reset(QgsWkbTypes.PolygonGeometry)
        
        # Get the rectangle bounds
        if self.start_point and self.end_point:
            rect = QgsRectangle(self.start_point, self.end_point)
            
            # Transform to WGS84
            map_crs = self.canvas.mapSettings().destinationCrs()
            wgs84_crs = QgsCoordinateReferenceSystem("EPSG:4326")
            
            if map_crs != wgs84_crs:
                transformer = QgsCoordinateTransform(map_crs, wgs84_crs, QgsProject.instance())
                rect_wgs84 = transformer.transformBoundingBox(rect)
            else:
                rect_wgs84 = rect
            
            # Emit rectangle as (min_lat, min_lon, max_lat, max_lon)
            self.rectangle_captured.emit(
                rect_wgs84.yMinimum(), rect_wgs84.xMinimum(),
                rect_wgs84.yMaximum(), rect_wgs84.xMaximum()
            )
    
    def _update_rubber_band(self):
        """Update the rubber band preview."""
        if not self.rubber_band or not self.start_point or not self.end_point:
            return
        
        self.rubber_band.reset(QgsWkbTypes.PolygonGeometry)
        
        # Create rectangle points
        rect = QgsRectangle(self.start_point, self.end_point)
        
        self.rubber_band.addPoint(QgsPointXY(rect.xMinimum(), rect.yMinimum()), False)
        self.rubber_band.addPoint(QgsPointXY(rect.xMinimum(), rect.yMaximum()), False)
        self.rubber_band.addPoint(QgsPointXY(rect.xMaximum(), rect.yMaximum()), False)
        self.rubber_band.addPoint(QgsPointXY(rect.xMaximum(), rect.yMinimum()), True)
    
    def deactivate(self):
        """Clean up when tool is deactivated."""
        if self.rubber_band:
            self.rubber_band.reset(QgsWkbTypes.PolygonGeometry)
        super().deactivate()


class ExtentRubberBand:
    """
    Utility class for managing a rubber band that shows the export extent.
    Creates and updates a persistent rubber band on the canvas.
    """
    
    def __init__(self, canvas):
        self.canvas = canvas
        self.rubber_band = None
    
    def create(self):
        """Create a new rubber band for extent visualization."""
        if self.rubber_band is None:
            self.rubber_band = QgsRubberBand(self.canvas, QgsWkbTypes.PolygonGeometry)
            self.rubber_band.setColor(QColor(0, 120, 255, 80))  # Blue with transparency
            self.rubber_band.setStrokeColor(QColor(0, 80, 200))
            self.rubber_band.setWidth(2)
    
    def set_extent(self, extent, from_crs='EPSG:3857'):
        """
        Set the rubber band to show the given extent.
        
        :param extent: QgsRectangle
        :param from_crs: CRS of the extent
        """
        self.create()
        self.rubber_band.reset(QgsWkbTypes.PolygonGeometry)
        
        # Transform extent to map CRS
        map_crs = self.canvas.mapSettings().destinationCrs()
        source_crs = QgsCoordinateReferenceSystem(from_crs)
        
        if map_crs != source_crs:
            transformer = QgsCoordinateTransform(source_crs, map_crs, QgsProject.instance())
            extent = transformer.transformBoundingBox(extent)
        
        # Add rectangle points
        self.rubber_band.addPoint(QgsPointXY(extent.xMinimum(), extent.yMinimum()), False)
        self.rubber_band.addPoint(QgsPointXY(extent.xMinimum(), extent.yMaximum()), False)
        self.rubber_band.addPoint(QgsPointXY(extent.xMaximum(), extent.yMaximum()), False)
        self.rubber_band.addPoint(QgsPointXY(extent.xMaximum(), extent.yMinimum()), True)
    
    def set_geometry(self, geometry, from_crs='EPSG:4326'):
        """
        Set the rubber band to show the given geometry.
        
        :param geometry: QgsGeometry
        :param from_crs: CRS of the geometry
        """
        self.create()
        self.rubber_band.reset(QgsWkbTypes.PolygonGeometry)
        
        # Transform geometry to map CRS
        map_crs = self.canvas.mapSettings().destinationCrs()
        source_crs = QgsCoordinateReferenceSystem(from_crs)
        
        if map_crs != source_crs:
            transformer = QgsCoordinateTransform(source_crs, map_crs, QgsProject.instance())
            geometry.transform(transformer)
        
        self.rubber_band.setToGeometry(geometry, None)
    
    def clear(self):
        """Clear and hide the rubber band."""
        if self.rubber_band:
            self.rubber_band.reset(QgsWkbTypes.PolygonGeometry)
    
    def remove(self):
        """Completely remove the rubber band."""
        if self.rubber_band:
            self.canvas.scene().removeItem(self.rubber_band)
            self.rubber_band = None


def get_canvas_extent(iface):
    """
    Get the current canvas extent in WGS84.
    
    :param iface: QGIS interface
    :returns: tuple (min_lat, min_lon, max_lat, max_lon)
    """
    canvas = iface.mapCanvas()
    extent = canvas.extent()
    
    # Transform to WGS84
    map_crs = canvas.mapSettings().destinationCrs()
    wgs84_crs = QgsCoordinateReferenceSystem("EPSG:4326")
    
    if map_crs != wgs84_crs:
        transformer = QgsCoordinateTransform(map_crs, wgs84_crs, QgsProject.instance())
        extent = transformer.transformBoundingBox(extent)
    
    return (extent.yMinimum(), extent.xMinimum(), extent.yMaximum(), extent.xMaximum())


def get_canvas_extent_3857(iface):
    """
    Get the current canvas extent in EPSG:3857.
    
    :param iface: QGIS interface
    :returns: QgsRectangle in EPSG:3857
    """
    canvas = iface.mapCanvas()
    extent = canvas.extent()
    
    # Transform to EPSG:3857
    map_crs = canvas.mapSettings().destinationCrs()
    target_crs = QgsCoordinateReferenceSystem("EPSG:3857")
    
    if map_crs != target_crs:
        transformer = QgsCoordinateTransform(map_crs, target_crs, QgsProject.instance())
        extent = transformer.transformBoundingBox(extent)
    
    return extent
