import os
import re
from qgis.core import (
    QgsVectorLayer, QgsVectorFileWriter, QgsCoordinateReferenceSystem,
    QgsField, QgsFields, QgsFeature, QgsProject
)
from qgis.PyQt.QtCore import QVariant


class KmlToShpConverter:
    def convert(self, kml_path, output_shp, target_crs_str='EPSG:4326'):
        """
        Converts KML/KMZ to SHP and attempts to parse attributes from HTML Description.
        """
        if not os.path.exists(kml_path):
            return False, "KML file not found"

        # 1. Load KML layer
        kml_layer = QgsVectorLayer(kml_path, "kml_temp", "ogr")
        if not kml_layer.isValid():
            return False, "Invalid KML file"

        # 2. Setup Target CRS
        crs = QgsCoordinateReferenceSystem(target_crs_str)
        if not crs.isValid():
            crs = QgsCoordinateReferenceSystem('EPSG:4326')

        # 3. Create a temporary layer to hold parsed fields
        # First, scan all features to find possible fields in Description
        all_new_fields = set()
        features = list(kml_layer.getFeatures())

        for feat in features:
            desc = str(
                feat['description']) if 'description' in feat.fields().names() else ""
            if desc:
                # LVT Plugin HTML template output matching
                matches = re.findall(
                    r'<td[^>]*>(.*?)</td>\s*<td[^>]*>(.*?)</td>',
                    desc,
                    re.IGNORECASE | re.DOTALL)

                # Filter out the header row if it's caught
                for key, val in matches:
                    clean_key = self._clean_field_name(key)
                    if clean_key and clean_key.lower() not in [
                            'th_ng_tin']:  # skip header row noise
                        all_new_fields.add(clean_key)

        # 4. Initialize Output SHP Writer
        options = QgsVectorFileWriter.SaveVectorOptions()
        options.driverName = "ESRI Shapefile"
        options.fileEncoding = "UTF-8"

        # Build new fields list
        new_fields = QgsFields()
        original_fields = kml_layer.fields()

        # Fields to remove generated by KML/OGR driver
        remove_fields_lower = [
            'description',
            'timestamp',
            'begin',
            'end',
            'altitudemode',
            'tessellate',
            'extrude',
            'visibility',
            'draworder',
            'icon']

        # Keep original fields except the unwanted ones
        for f in original_fields:
            if f.name().lower() not in remove_fields_lower:
                new_fields.append(f)

        for new_f in all_new_fields:
            if new_f.lower() not in [f.name().lower() for f in new_fields]:
                new_fields.append(QgsField(new_f, QVariant.String))

        writer = QgsVectorFileWriter.create(
            output_shp, new_fields, kml_layer.wkbType(), crs,
            QgsProject.instance().transformContext(), options
        )

        if writer.hasError():
            return False, f"Writer Error: {writer.errorMessage()}"

        # 5. Process and Write Features
        for feat in features:
            new_feat = QgsFeature(new_fields)
            new_feat.setGeometry(feat.geometry())

            # Copy original attributes that were kept
            for i in range(original_fields.count()):
                f_name = original_fields.at(i).name()
                if f_name.lower() not in remove_fields_lower:
                    new_idx = new_fields.indexFromName(f_name)
                    if new_idx != -1:
                        new_feat.setAttribute(new_idx, feat.attributes()[i])

            # Parse and add dynamic attributes
            desc = str(
                feat['description']) if 'description' in feat.fields().names() else ""
            if desc:
                matches = re.findall(
                    r'<td[^>]*>(.*?)</td>\s*<td[^>]*>(.*?)</td>',
                    desc,
                    re.IGNORECASE | re.DOTALL)

                for key, val in matches:
                    clean_key = self._clean_field_name(key)
                    # Strip HTML tags from value
                    clean_val = re.sub(r'<.*?>', '', val).strip()
                    # Find index of this field
                    f_idx = new_fields.indexFromName(clean_key)
                    if f_idx != -1:
                        new_feat.setAttribute(f_idx, clean_val)

            writer.addFeature(new_feat)

        del writer
        return True, "Success"

    def _clean_field_name(self, name):
        # Remove HTML tags and special characters for SHP compatibility (max 10
        # chars usually)
        clean = re.sub(r'<.*?>', '', name).strip()
        clean = re.sub(r'[^a-zA-Z0-9_]', '_', clean)
        return clean[:10]
