# -*- coding: utf-8 -*-

import os

from qgis.core import (
    QgsProject,
    QgsVectorLayer,
    QgsField,
    QgsWkbTypes
)

from qgis.PyQt.QtWidgets import (
    QAction,
    QMessageBox,
    QInputDialog
)

from qgis.PyQt.QtGui import QIcon
from PyQt5.QtCore import QVariant


class MJChainage:

    def __init__(self, iface):
        self.iface = iface
        self.action = None
        self.toolbar = None
        self.menu = None

    def initGui(self):

        icon_path = os.path.join(
            os.path.dirname(__file__),
            "icon.png"
        )

        self.action = QAction(
            QIcon(icon_path),
            "Calculate Chainage By MJ",
            self.iface.mainWindow()
        )

        self.action.triggered.connect(self.run)

        # Toolbar
        self.toolbar = self.iface.addToolBar("MJ Chainage")
        self.toolbar.addAction(self.action)

        # MJNETWORK Menu
        menubar = self.iface.mainWindow().menuBar()

        self.menu = None

        for action in menubar.actions():
            if action.text() == "MJNETWORK":
                self.menu = action.menu()
                break

        if self.menu:
            self.menu.addAction(self.action)
        else:
            self.menu = menubar.addMenu("MJNETWORK")
            self.menu.addAction(self.action)

    def unload(self):

        try:
            if self.menu:
                self.menu.removeAction(self.action)
        except Exception:
            pass

        try:
            if self.toolbar:
                self.toolbar.removeAction(self.action)
        except Exception:
            pass

        try:
            self.iface.removeToolBarIcon(self.action)
        except Exception:
            pass

    def run(self):

        # Find Point and Line Layers
        point_layers = []
        line_layers = []

        for layer in QgsProject.instance().mapLayers().values():

            if not isinstance(layer, QgsVectorLayer):
                continue

            if layer.geometryType() == QgsWkbTypes.PointGeometry:
                point_layers.append(layer)

            elif layer.geometryType() == QgsWkbTypes.LineGeometry:
                line_layers.append(layer)

        # Validation
        if not point_layers:
            QMessageBox.warning(
                self.iface.mainWindow(),
                "MJ Chainage",
                "No Point Layer Found!"
            )
            return

        if not line_layers:
            QMessageBox.warning(
                self.iface.mainWindow(),
                "MJ Chainage",
                "No Line Layer Found!"
            )
            return

        # Select Point Layer
        point_names = [layer.name() for layer in point_layers]

        point_name, ok = QInputDialog.getItem(
            self.iface.mainWindow(),
            "Select Point Layer",
            "Point Layer:",
            point_names,
            0,
            False
        )

        if not ok:
            return

        point_layer = point_layers[
            point_names.index(point_name)
        ]

        # Select Line Layer
        line_names = [layer.name() for layer in line_layers]

        line_name, ok = QInputDialog.getItem(
            self.iface.mainWindow(),
            "Select Line Layer",
            "Line Layer:",
            line_names,
            0,
            False
        )

        if not ok:
            return

        line_layer = line_layers[
            line_names.index(line_name)
        ]

        # Start Editing
        if not point_layer.isEditable():
            point_layer.startEditing()

        # Create Fields
        field_names = [f.name() for f in point_layer.fields()]

        if "chainage" not in field_names:
            point_layer.addAttribute(
                QgsField(
                    "chainage",
                    QVariant.Double,
                    "double",
                    20,
                    4
                )
            )

        if "km_chainage" not in field_names:
            point_layer.addAttribute(
                QgsField(
                    "km_chainage",
                    QVariant.String
                )
            )

        point_layer.updateFields()

        chainage_idx = point_layer.fields().indexFromName("chainage")
        km_chainage_idx = point_layer.fields().indexFromName("km_chainage")
        total_points = 0

        # Calculate Chainage
        for point in point_layer.getFeatures():

            point_geom = point.geometry()

            nearest_line = None
            min_distance = float("inf")

            for line in line_layer.getFeatures():

                line_geom = line.geometry()

                distance = point_geom.distance(line_geom)

                if distance < min_distance:
                    min_distance = distance
                    nearest_line = line

            if nearest_line:

                chainage = nearest_line.geometry().lineLocatePoint(
                    point_geom
                )

                km_chainage = round(chainage / 1000.0, 4)

                point_layer.changeAttributeValue(
                    point.id(),
                    chainage_idx,
                    round(chainage, 4)
                )

                point_layer.changeAttributeValue(
                    point.id(),
                    km_chainage_idx,
                    km_chainage
                )

                total_points += 1

        point_layer.commitChanges()

        QMessageBox.information(
            self.iface.mainWindow(),
            "MJ Chainage",
            f"Chainage calculated successfully!\n\nProcessed Points: {total_points}"
        )
