import os
import shutil

from qgis.core import (
    QgsRasterLayer,
    QgsProject,
    QgsCoordinateReferenceSystem,
    QgsProcessingFeedback,
)
from qgis.gui import QgsProjectionSelectionDialog
from qgis import processing
from qgis.PyQt.QtWidgets import QMessageBox, QFileDialog


EPSG_3857 = QgsCoordinateReferenceSystem("EPSG:3857")



def load_jpg_jgw_and_convert(iface):
    """
    Load a JPG + JGW, validate it, and convert to GeoTIFF in EPSG:3857.
    """

    from qgis.PyQt.QtWidgets import QFileDialog

    # -----------------------------------
    # Select JPG
    # -----------------------------------
    path, _ = QFileDialog.getOpenFileName(
        iface.mainWindow(),
        "Select JPG file",
        "",
        "JPG (*.jpg *.jpeg)"
    )
    if not path:
        return

    base = os.path.basename(path)
    base_no_ext = os.path.splitext(path)[0]

    # -----------------------------------
    # Validate JGW
    # -----------------------------------
    jgw_candidates = [
        base_no_ext + ".jgw",
        base_no_ext + ".jpgw"
    ]

    if not any(os.path.exists(j) for j in jgw_candidates):
        QMessageBox.warning(
            iface.mainWindow(),
            "Missing JGW",
            "This JPG does not have a matching world file (.jgw or .jpgw)."
        )
        return

    # -----------------------------------
    # Load raster
    # -----------------------------------
    raster = QgsRasterLayer(path, base)
    if not raster.isValid():
        QMessageBox.warning(
            iface.mainWindow(),
            "Load Error",
            "Could not load JPG + JGW."
        )
        return

    raster.setCrs(EPSG_3857)
    QgsProject.instance().addMapLayer(raster)

    # -----------------------------------
    # Output path
    # -----------------------------------
    out_path = os.path.join(
        os.path.dirname(path),
        base.replace(".jpg", "_converted.tif").replace(".jpeg", "_converted.tif")
    )

    # -----------------------------------
    # Convert to GeoTIFF
    # -----------------------------------
    try:
        processing.run("gdal:translate", {
            "INPUT": path,
            "TARGET_CRS": EPSG_3857.authid(),
            "OUTPUT": out_path
        })
    except Exception as e:
        QMessageBox.warning(
            iface.mainWindow(),
            "Conversion Failed",
            str(e)
        )
        return

    # -----------------------------------
    # Load output
    # -----------------------------------
    out_layer = QgsRasterLayer(out_path, os.path.basename(out_path))
    if out_layer.isValid():
        QgsProject.instance().addMapLayer(out_layer)

            # Zoom to new layer
        iface.mapCanvas().setExtent(out_layer.extent())
        iface.mapCanvas().refresh()

    QMessageBox.information(
        iface.mainWindow(),
        "Success",
        f"Converted to GeoTIFF:\n{out_path}"
    )

def load_sid_and_convert(iface):
    """
    Load a MrSID file, validate CRS, reproject to EPSG:3857,
    save as GeoTIFF, load it, and zoom to the result.
    """

    from qgis.PyQt.QtWidgets import QFileDialog

    # -----------------------------------
    # Select SID
    # -----------------------------------
    path, _ = QFileDialog.getOpenFileName(
        iface.mainWindow(),
        "Select MrSID file",
        "",
        "MrSID (*.sid)"
    )
    if not path:
        return

    base = os.path.basename(path)
    base_no_ext = os.path.splitext(base)[0]

    # -----------------------------------
    # Load SID layer (to inspect CRS)
    # -----------------------------------
    sid_layer = QgsRasterLayer(path, base)
    if not sid_layer.isValid():
        QMessageBox.warning(
            iface.mainWindow(),
            "Invalid SID",
            "The selected MrSID file could not be loaded."
        )
        return

    if not sid_layer.crs().isValid():
        QMessageBox.warning(
            iface.mainWindow(),
            "Unknown CRS",
            "This MrSID file does not have a readable CRS."
        )
        return

    source_crs = sid_layer.crs().authid()

    # -----------------------------------
    # Output path
    # -----------------------------------
    out_path = os.path.join(
        os.path.dirname(path),
        f"{base_no_ext}_EPSG3857.tif"
    )

    # -----------------------------------
    # Reproject using GDAL warp
    # -----------------------------------
    try:
        processing.run("gdal:warpreproject", {
            "INPUT": path,
            "SOURCE_CRS": source_crs,
            "TARGET_CRS": EPSG_3857.authid(),
            "RESAMPLING": 0,  # nearest neighbour (safe default)
            "NODATA": None,
            "TARGET_RESOLUTION": None,
            "OPTIONS": "",
            "DATA_TYPE": 0,
            "TARGET_EXTENT": None,
            "TARGET_EXTENT_CRS": None,
            "MULTITHREADING": True,
            "EXTRA": "",
            "OUTPUT": out_path,
        })
    except Exception as e:
        QMessageBox.warning(
            iface.mainWindow(),
            "SID Conversion Failed",
            str(e)
        )
        return

    # -----------------------------------
    # Load output and zoom
    # -----------------------------------
    out_layer = QgsRasterLayer(out_path, os.path.basename(out_path))
    if not out_layer.isValid():
        QMessageBox.warning(
            iface.mainWindow(),
            "Load Error",
            "The converted GeoTIFF could not be loaded."
        )
        return

    QgsProject.instance().addMapLayer(out_layer)

    iface.mapCanvas().setExtent(out_layer.extent())
    iface.mapCanvas().refresh()

    QMessageBox.information(
        iface.mainWindow(),
        "SID Conversion Complete",
        f"SID successfully converted to EPSG:3857:\n{out_path}"
    )



def reproject_geotiff_to_3857(iface):
    # --------------------------------------------------
    # 1. Select input GeoTIFF
    # --------------------------------------------------
    in_path, _ = QFileDialog.getOpenFileName(
        iface.mainWindow(),
        "Select GeoTIFF to Reproject to EPSG:3857",
        "",
        "GeoTIFF (*.tif *.tiff)"
    )
    if not in_path:
        return

    src_layer = QgsRasterLayer(in_path, os.path.basename(in_path))
    if not src_layer.isValid():
        QMessageBox.warning(
            iface.mainWindow(),
            "Invalid Raster",
            "Could not load the selected raster."
        )
        return

    # --------------------------------------------------
    # 2. Determine source CRS (prompt only if missing)
    # --------------------------------------------------
    src_crs = src_layer.crs()
    if not src_crs.isValid():
        dlg = QgsProjectionSelectionDialog(iface.mainWindow())
        dlg.setWindowTitle("Select Source CRS")
        if not dlg.exec_():
            return
        src_crs = dlg.crs()

    # --------------------------------------------------
    # 3. Build output path automatically
    # --------------------------------------------------
    base, ext = os.path.splitext(in_path)
    out_path = f"{base}_EPSG3857.tif"

    # Ensure clean overwrite
    if os.path.exists(out_path):
        try:
            os.remove(out_path)
        except Exception as e:
            QMessageBox.critical(
                iface.mainWindow(),
                "File Error",
                f"Could not overwrite existing file:\n{out_path}\n\n{e}"
            )
            return

    # --------------------------------------------------
    # 4. Reproject using GDAL warp
    # --------------------------------------------------
    feedback = QgsProcessingFeedback()

    params = {
        "INPUT": in_path,
        "TARGET_CRS": EPSG_3857.authid(),
        "RESAMPLING": 0,                # nearest neighbour
        "NODATA": None,
        "TARGET_RESOLUTION": None,
        "OPTIONS": "COMPRESS=LZW",
        "DATA_TYPE": 0,
        "TARGET_EXTENT": None,
        "TARGET_EXTENT_CRS": None,
        "MULTITHREADING": True,
        "EXTRA": "",
        "OUTPUT": out_path,
    }

    # Only override SOURCE_CRS if the raster truly had none
    if not src_layer.crs().isValid():
        params["SOURCE_CRS"] = src_crs.authid()

    try:
        processing.run("gdal:warpreproject", params, feedback=feedback)
    except Exception as e:
        QMessageBox.critical(
            iface.mainWindow(),
            "Reprojection Failed",
            str(e)
        )
        return

    # --------------------------------------------------
    # 5. Verify output + load
    # --------------------------------------------------
    if not os.path.exists(out_path) or os.path.getsize(out_path) == 0:
        QMessageBox.critical(
            iface.mainWindow(),
            "GDAL Error",
            "Reprojection failed: output file was not created."
        )
        return

    out_layer = QgsRasterLayer(out_path, os.path.basename(out_path))
    if not out_layer.isValid():
        QMessageBox.warning(
            iface.mainWindow(),
            "Load Error",
            "Reprojected raster could not be loaded."
        )
        return

    QgsProject.instance().addMapLayer(out_layer)
    iface.mapCanvas().setExtent(out_layer.extent())
    iface.mapCanvas().refresh()

    QMessageBox.information(
        iface.mainWindow(),
        "Reprojection Complete",
        f"GeoTIFF successfully reprojected to EPSG:3857:\n\n{out_path}"
    )


def add_ai_output_tif(iface):
    # --------------------------------------------------
    # 1. Select GeoTIFF
    # --------------------------------------------------
    in_path, _ = QFileDialog.getOpenFileName(
        iface.mainWindow(),
        "Select Asphalt Intelligence Output (EPSG:3857)",
        "",
        "GeoTIFF (*.tif *.tiff)"
    )
    if not in_path:
        return

    # --------------------------------------------------
    # 2. Validate raster + CRS
    # --------------------------------------------------
    layer = QgsRasterLayer(in_path, os.path.basename(in_path))
    if not layer.isValid():
        QMessageBox.warning(
            iface.mainWindow(),
            "Invalid Raster",
            "The selected file could not be loaded."
        )
        return

    if layer.crs().authid() != "EPSG:3857":
        QMessageBox.warning(
            iface.mainWindow(),
            "CRS Mismatch",
            "This GeoTIFF is not in EPSG:3857.\n\n"
            "Please reproject it before adding it as an Asphalt Intelligence output."
        )
        return

    # --------------------------------------------------
    # 3. Derive project AI folder (same pattern as others)
    # --------------------------------------------------
    project_path = QgsProject.instance().fileName()
    if not project_path:
        QMessageBox.warning(
            iface.mainWindow(),
            "Project Not Saved",
            "Please save the QGIS project before adding outputs."
        )
        return

    project_folder = os.path.splitext(project_path)[0] + "_AI_Files"
    os.makedirs(project_folder, exist_ok=True)

    dst_path = os.path.join(project_folder, os.path.basename(in_path))

    # --------------------------------------------------
    # 4. Copy file
    # --------------------------------------------------
    try:
        shutil.copy2(in_path, dst_path)
    except Exception as e:
        QMessageBox.critical(
            iface.mainWindow(),
            "File Copy Failed",
            f"Could not copy file to project folder:\n\n{e}"
        )
        return

    # --------------------------------------------------
    # 5. Load copied layer + zoom
    # --------------------------------------------------
    out_layer = QgsRasterLayer(dst_path, os.path.basename(dst_path))
    if not out_layer.isValid():
        QMessageBox.warning(
            iface.mainWindow(),
            "Load Error",
            "Copied GeoTIFF could not be loaded."
        )
        return

    QgsProject.instance().addMapLayer(out_layer)
    iface.mapCanvas().setExtent(out_layer.extent())
    iface.mapCanvas().refresh()

    # --------------------------------------------------
    # 6. Success dialog
    # --------------------------------------------------
    QMessageBox.information(
        iface.mainWindow(),
        "Asphalt Intelligence Output Added",
        f"GeoTIFF successfully added to the project:\n\n{dst_path}"
    )
