import traceback
import logging
import json
from typing import Protocol, Literal
from osgeo import ogr, gdal, osr
import time
import re
from datetime import datetime

class UatLimitGet(Protocol):
    def __call__(self, siruta: str) -> dict[str, str] | str: ...

class RulesWriter(Protocol):
    def validation_pass(self, rule: dict[str, str]) -> None: ...
    def validation_fail(self, rule: dict[str, str], verify: str = "-") -> None: ...
    def validation_error(self, rule: dict[str, str], verify: str = "-") -> None: ...


class GpkgDataRules:
    def __init__(self, logger: logging.Logger, loop_limit: float, rules_writer: RulesWriter):
        self.logger: logging.Logger = logger
        self.loopLimit: float = loop_limit
        self.rulesWriter: RulesWriter = rules_writer

    # Rule type 20
    def layers_contain_data(self,
            rule: dict[str, str],
            documentation_gpkg: gdal.Dataset,
            plan_type: Literal["PUG", "PUZ", "PUD", "PATJ", "PMUD"]) -> bool:
        """Verify if the GPKG layers contain data."""
        try:
            if plan_type in ["PUG", "PUZ", "PUD", "PATJ", "PMUD"]:
                layers: list[str] = rule["valoare_regula"].split(",")
                layersFailed: list[str] = []

                for layer in layers:
                    time.sleep(self.loopLimit)
                    gpkgLayer: ogr.Layer = documentation_gpkg.GetLayerByName(layer)
                    if gpkgLayer.GetFeatureCount() == 0:
                        layersFailed.append(layer)

                if layersFailed:
                    self.rulesWriter.validation_fail(rule=rule, verify=f"Verificati straturile fisierului GPKG sa contina date: {layersFailed}")
                    return int(rule['tip_alerta_id']) != 1
                else:
                    self.rulesWriter.validation_pass(rule=rule)
                    return True

        except Exception:
            traceBack = traceback.format_exc()
            self.logger.error(
                f"[{self.__class__.__name__} - {self.layers_contain_data.__name__}] "
                f"Failed to verify if the layers contain data.\n{traceBack}")
            self.rulesWriter.validation_error(rule=rule)
            return int(rule['tip_alerta_id']) != 1

    # Rule type 21
    def columns_contain_data(self,
            rule: dict[str, str],
            documentation_gpkg: gdal.Dataset,
            plan_type: Literal["PUG", "PUZ", "PUD", "PATJ", "PMUD"]) -> bool:
        """Verifies if the layers columns contain data and if the layer contains data."""
        try:
            if plan_type in ["PUG", "PUZ", "PUD", "PATJ", "PMUD"]:
                layersColumns: dict[str, list[str]] = json.loads(rule["valoare_regula"])

                layersNoData: list[str] = []
                layersColumnsNoData: dict[str, dict[str, list[int]]] = {}

                supportsIsFieldNull = hasattr(ogr.Feature, 'IsFieldNull')

                for layer, columns in layersColumns.items():
                    time.sleep(self.loopLimit)

                    gpkgLayer: ogr.Layer = documentation_gpkg.GetLayerByName(layer)
                    if gpkgLayer.GetFeatureCount() == 0:
                        layersNoData.append(layer)
                        continue

                    gpkgLayerDefn: ogr.FeatureDefn = gpkgLayer.GetLayerDefn()
                    columnIndices: dict[str, int] = {}
                    missingColumns: list[str] = []
                    for column in columns:
                        idx = gpkgLayerDefn.GetFieldIndex(column)
                        if idx != -1:
                            columnIndices[column] = idx
                        else:
                            missingColumns.append(column)

                    if missingColumns:
                        layerEntry = layersColumnsNoData.setdefault(layer, {})
                        for col in missingColumns:
                            layerEntry[col] = []

                    gpkgLayer.ResetReading()
                    columnMissingFids: dict[str, list[int]] = {col: [] for col in columnIndices}

                    for feature in gpkgLayer:
                        time.sleep(self.loopLimit)
                        fid: int = feature.GetFID()

                        for column, fieldIndex in columnIndices.items():
                            if len(columnMissingFids[column]) >= 100:
                                continue
                            if self._is_field_missing(feature, fieldIndex, supportsIsFieldNull):
                                columnMissingFids[column].append(fid)

                    layerBadColumns = {col: fids for col, fids in columnMissingFids.items() if fids}
                    if layerBadColumns:
                        layersColumnsNoData[layer] = layerBadColumns

            if layersColumnsNoData and layersNoData:
                self.rulesWriter.validation_fail(
                    rule=rule,
                    verify=f"Verificati straturile din fisierului GPKG sa contina date: {layersNoData}\n"
                           f"Verificati coloanele straturilor din fisierului GPKG sa contina date: {layersColumnsNoData}")
                return int(rule['tip_alerta_id']) != 1
            elif layersNoData:
                self.rulesWriter.validation_fail(
                    rule=rule,
                    verify=f"Verificati straturile fisierului GPKG sa contina date: {layersNoData}")
                return int(rule['tip_alerta_id']) != 1
            elif layersColumnsNoData:
                self.rulesWriter.validation_fail(
                    rule=rule,
                    verify=f"Verificati coloanele straturilor din fisierului GPKG sa contina date: {layersColumnsNoData}")
                return int(rule['tip_alerta_id']) != 1
            else:
                self.rulesWriter.validation_pass(rule=rule)
                return True

        except Exception:
            traceBack = traceback.format_exc()
            self.logger.error(
                f"[{self.__class__.__name__} - {self.columns_contain_data.__name__}] "
                f"Failed to verify if the layers columns contain data.\n{traceBack}")
            self.rulesWriter.validation_error(rule=rule)
            return int(rule['tip_alerta_id']) != 1

    def _is_field_missing(self, feature: ogr.Feature, fieldIndex: int, supportsIsFieldNull: bool) -> bool:
        if supportsIsFieldNull and feature.IsFieldNull(fieldIndex):
            return True
        if not feature.IsFieldSet(fieldIndex):
            return True
        value = feature.GetField(fieldIndex)
        if value is None:
            return True
        if isinstance(value, str) and value.strip() == '':
            return True
        return False

    # Rule type 23
    def columns_data_validation(self,
            rule: dict[str, str],
            documentation_gpkg: gdal.Dataset,
            template_metadata: dict[str, list[str] | dict[str, dict[str, str]] | dict[str, str]],
            plan_type: Literal["PUG", "PUZ", "PUD", "PATJ", "PMUD"]) -> bool:
        try:
            if plan_type in ["PUG", "PUZ", "PUD", "PATJ", "PMUD"]:
                layersColumnsWrongData: dict[str, dict[str, list[int]]] = {}
                layersColumns: dict[str, list[str]] = json.loads(rule["valoare_regula"])

                for layer, columns in layersColumns.items():
                    time.sleep(self.loopLimit)

                    gpkgLayer: ogr.Layer = documentation_gpkg.GetLayerByName(layer.strip())
                    if gpkgLayer.GetFeatureCount() == 0:
                        continue

                    gpkgLayerDefn: ogr.FeatureDefn = gpkgLayer.GetLayerDefn()
                    columnIndices: dict[str, int] = {
                        column.strip(): idx
                        for column in columns
                        if (idx := gpkgLayerDefn.GetFieldIndex(column.strip())) != -1
                    }

                    if not columnIndices:
                        continue

                    gpkgLayer.ResetReading()
                    columnWrongFids: dict[str, list[int]] = {col: [] for col in columnIndices}

                    for feature in gpkgLayer:
                        time.sleep(self.loopLimit)
                        fid = feature.GetFID()

                        for column, fieldIndex in columnIndices.items():
                            value: str = feature.GetField(fieldIndex)

                            if value is None or (isinstance(value, str) and value.strip() == ''):
                                columnWrongFids[column].append(fid)
                                continue

                            isValid = True

                            if column == "NivelPlan":
                                isValid = value.lower().strip() in template_metadata["NivelPlan"]
                            elif column == "HCL":
                                isValid = bool(re.match(r'^\d{1,6}$', str(value).strip()))
                            elif column in ["Data_aprob", "Data_exp", "Revizie"]:
                                isValid = any(
                                    self._try_parse_date(str(value).strip(), fmt)
                                    for fmt in template_metadata["DateFormats"]
                                )
                            elif column in ["ArieADM", "ArieINT", "AriePlan", "Arie_ZF", "Arie_ZRS", "Lungime"]:
                                isValid = bool(re.match(r'^\d*\.\d{1,2}$', str(value).strip()))
                            elif column in ["Cod_ZF", "Cod_ZRS", "Cod_ZF_ZRS"]:
                                isValid = value.strip() in template_metadata["Cod_ZF_ZRS"]
                            elif column == "HILUCS_N1":
                                isValid = value.strip() in template_metadata["Hilucs"]
                            elif column == "Tip_zona":
                                if layer == "RegulamentLocalUrbanism":
                                    isValid = value.strip() in template_metadata["TipZona"]
                                elif layer == "RegulamentLocalUrbanismDetaliat":
                                    isValid = value.strip() in template_metadata["TipSubzona"]
                            elif column == "Sursa_revizie":
                                isValid = bool(re.match(
                                    r'^\d{1,6}\/(0[1-9]|[1-2][0-9]|3[0-1])\.(0[1-9]|1[0-2])\.\d{4}$',
                                    str(value).strip()))
                            elif column == "Tip_RTE":
                                isValid = value.strip() in template_metadata["TipRTE"]
                            elif column == "Subtip_RTE":
                                isValid = value.strip() in template_metadata["SubtipRTE"]
                            elif column == "Stadiu_RTE":
                                isValid = value.strip() in template_metadata["StadiuRTE"]
                            elif column == "Tip_Ccom":
                                isValid = value.strip() in template_metadata["TipCcom"]
                            elif column == "Subtip_Ccom":
                                isValid = value.strip() in template_metadata["SubtipCcom"]
                            elif column == "Stadiu_Ccom":
                                isValid = value.strip() in template_metadata["StadiuCcom"]
                            elif column == "Tip_RU":
                                isValid = value.strip() in template_metadata["TipRU"]

                            if not isValid:
                                columnWrongFids[column].append(fid)

                    layerBadColumns = {col: fids for col, fids in columnWrongFids.items() if fids}
                    if layerBadColumns:
                        layersColumnsWrongData[layer] = layerBadColumns

            if layersColumnsWrongData:
                self.rulesWriter.validation_fail(
                    rule=rule,
                    verify=f"Verificati coloanele straturilor din fisierului GPKG sa contina datele corecte: {layersColumnsWrongData}")
                return int(rule['tip_alerta_id']) != 1
            else:
                self.rulesWriter.validation_pass(rule=rule)
                return True

        except Exception:
            traceBack = traceback.format_exc()
            self.logger.error(
                f"[{self.__class__.__name__} - {self.columns_data_validation.__name__}] "
                f"Failed to verify if layers columns data is correct.\n{traceBack}")
            self.rulesWriter.validation_error(rule=rule)
            return int(rule['tip_alerta_id']) != 1

    def _try_parse_date(self, value: str, fmt: str) -> bool:
        try:
            datetime.strptime(value, fmt)
            return True
        except (ValueError, TypeError):
            return False

    # Rule type 24
    def temporal_data_validation(self,
            rule: dict[str, str],
            documentation_gpkg: gdal.Dataset,
            template_metadata: dict[str, list[str] | dict[str, dict[str, str]] | dict[str, str]],
            plan_type: Literal["PUG", "PUZ", "PUD", "PATJ", "PMUD"]) -> bool:
        """Verifies if the temporal dates from the layers columns are correct."""
        try:
            if plan_type in ["PUG", "PUZ", "PUD", "PATJ", "PMUD"]:
                currentDate = datetime.now().date()
                dateFormats: list[str] = template_metadata["DateFormats"]

                layersColumnsNames: dict[str, list[str]] = json.loads(rule["valoare_regula"])
                layersColumnsWrongDate: dict[str, list[int]] = {}

                for layer, columns in layersColumnsNames.items():
                    time.sleep(self.loopLimit)

                    gpkgLayer: ogr.Layer = documentation_gpkg.GetLayerByName(layer)
                    gpkgLayerDefn: ogr.FeatureDefn = gpkgLayer.GetLayerDefn()

                    columnIndices: dict[str, int] = {
                        col: idx
                        for col in columns
                        if (idx := gpkgLayerDefn.GetFieldIndex(col)) != -1
                    }

                    gpkgLayer.ResetReading()
                    failedIds: list[int] = []

                    for feature in gpkgLayer:
                        time.sleep(self.loopLimit)
                        fid: int = feature.GetFID()
                        if len(failedIds) >= 100:
                            break

                        if "Data_aprob" in columnIndices and "Data_exp" in columnIndices:
                            dateAprob = self._parse_date_field(feature, columnIndices["Data_aprob"], dateFormats)
                            dateExp   = self._parse_date_field(feature, columnIndices["Data_exp"],   dateFormats)
                            if dateAprob is None or dateExp is None:
                                failedIds.append(fid)
                            elif not (dateAprob < currentDate < dateExp):
                                failedIds.append(fid)
                        elif "Data_exp" in columnIndices:
                            dateExp = self._parse_date_field(feature, columnIndices["Data_exp"], dateFormats)
                            if dateExp is None:
                                failedIds.append(fid)
                            elif currentDate >= dateExp:
                                failedIds.append(fid)
                        elif "Revizie" in columnIndices:
                            revizie = self._parse_date_field(feature, columnIndices["Revizie"], dateFormats)
                            if revizie is None:
                                failedIds.append(fid)
                            elif currentDate >= revizie:
                                failedIds.append(fid)

                    if failedIds:
                        layersColumnsWrongDate[layer] = failedIds

            if layersColumnsWrongDate:
                self.rulesWriter.validation_fail(
                    rule=rule,
                    verify=f"Verificati straturile din fisierului GPKG sa aiba datele temporale corecte: {layersColumnsWrongDate}")
                return int(rule['tip_alerta_id']) != 1
            else:
                self.rulesWriter.validation_pass(rule=rule)
                return True

        except Exception:
            traceBack = traceback.format_exc()
            self.logger.error(
                f"[{self.__class__.__name__} - {self.temporal_data_validation.__name__}] "
                f"Failed to verify if layers columns temporal dates are correct.\n{traceBack}")
            self.rulesWriter.validation_error(rule=rule)
            return int(rule['tip_alerta_id']) != 1

    def _parse_date_field(self, feature: ogr.Feature, fieldIndex: int, dateFormats: list[str]) -> datetime | None:
        """Reads a date field and parses it. Returns None if missing, unset, or unparseable."""
        try:
            if not feature.IsFieldSet(fieldIndex) or feature.IsFieldNull(fieldIndex):
                return None
            value = feature.GetField(fieldIndex)
            if not value or (isinstance(value, str) and not value.strip()):
                return None
            for fmt in dateFormats:
                try:
                    return datetime.strptime(str(value).strip(), fmt).date()
                except (ValueError, TypeError):
                    continue
            return None
        except Exception:
            return None

    # Rule type 25
    def hilucs_data_correlation(self,
            rule: dict[str, str],
            documentation_gpkg: gdal.Dataset,
            template_metadata: dict[str, list[str] | dict[str, dict[str, str]] | dict[str, str]],
            plan_type: Literal["PUG", "PUZ", "PUD", "PATJ", "PMUD"]) -> bool:
        """Verifies if the HILUCS are named and correlated based on OMDLPA904."""
        try:
            if plan_type in ["PUG", "PUZ", "PUD", "PATJ", "PMUD"]:
                layerColumnsHilucsWrong: dict[str, dict[str, list[int]]] = {}
                layersColumnsNames: dict[str, list[str]] = json.loads(rule["valoare_regula"])

                for layer, columns in layersColumnsNames.items():
                    time.sleep(self.loopLimit)

                    gpkgLayer: ogr.Layer = documentation_gpkg.GetLayerByName(layer)
                    gpkgLayerDefn: ogr.FeatureDefn = gpkgLayer.GetLayerDefn()

                    fieldIdH1 = gpkgLayerDefn.GetFieldIndex(columns[0])
                    fieldIdH2 = gpkgLayerDefn.GetFieldIndex(columns[1])
                    fieldIdH3 = gpkgLayerDefn.GetFieldIndex(columns[2])

                    gpkgLayer.ResetReading()

                    h1_wrong: set[int] = set()
                    h2_wrong: set[int] = set()
                    h3_wrong: set[int] = set()

                    for feature in gpkgLayer:
                        time.sleep(self.loopLimit)
                        fid: int = feature.GetFID()

                        h1Value = self._read_field(feature, fieldIdH1)
                        h2Value = self._read_field(feature, fieldIdH2)
                        h3Value = self._read_field(feature, fieldIdH3)

                        if h1Value is None: h1_wrong.add(fid)
                        if h2Value is None: h2_wrong.add(fid)
                        if h3Value is None: h3_wrong.add(fid)

                        if h1Value and h1Value not in template_metadata["Hilucs"]:
                            h1_wrong.add(fid)
                        if h2Value and h2Value not in template_metadata["Hilucs"]:
                            h2_wrong.add(fid)
                        if h3Value and h3Value not in template_metadata["Hilucs"]:
                            h3_wrong.add(fid)

                        if h1Value and h2Value:
                            if not (h2Value in template_metadata["Hilucs"] and
                                    h1Value in template_metadata["Hilucs"].get(h2Value, [])):
                                h1_wrong.add(fid)
                                h2_wrong.add(fid)

                        if h2Value and h3Value:
                            if not (h3Value in template_metadata["Hilucs"] and
                                    h2Value in template_metadata["Hilucs"].get(h3Value, [])):
                                h2_wrong.add(fid)
                                h3_wrong.add(fid)

                    layerBadColumns: dict[str, list[int]] = {}
                    if h1_wrong: layerBadColumns[columns[0]] = sorted(h1_wrong)[:100]
                    if h2_wrong: layerBadColumns[columns[1]] = sorted(h2_wrong)[:100]
                    if h3_wrong: layerBadColumns[columns[2]] = sorted(h3_wrong)[:100]

                    if layerBadColumns:
                        layerColumnsHilucsWrong[layer] = layerBadColumns

            if layerColumnsHilucsWrong:
                self.rulesWriter.validation_fail(
                    rule=rule,
                    verify=f"Verificati straturile din fisierului GPKG sa aiba HILUCS-urile denumite sau corelate corect: {layerColumnsHilucsWrong}")
                return int(rule['tip_alerta_id']) != 1
            else:
                self.rulesWriter.validation_pass(rule=rule)
                return True

        except Exception:
            traceBack = traceback.format_exc()
            self.logger.error(
                f"[{self.__class__.__name__} - {self.hilucs_data_correlation.__name__}] "
                f"Failed to verify if layers columns hilucs data is correct.\n{traceBack}")
            self.rulesWriter.validation_error(rule=rule)
            return int(rule['tip_alerta_id']) != 1

    def _read_field(self, feature: ogr.Feature, fieldIndex: int) -> str | None:
        """Returns the field value as a string, or None if missing/null/empty."""
        if fieldIndex < 0:
            return None
        if not feature.IsFieldSet(fieldIndex) or feature.IsFieldNull(fieldIndex):
            return None
        value = feature.GetField(fieldIndex)
        if value is None or (isinstance(value, str) and not value.strip()):
            return None
        return value

    # Rule type 26
    def zonal_code_correlation(self,
            rule: dict[str, str],
            documentation_gpkg: gdal.Dataset,
            plan_type: Literal["PUG", "PUZ", "PUD", "PATJ", "PMUD"]) -> bool:
        """Verifies if the zonal codes are correlated based on OMDLPA 904."""
        try:
            if plan_type in ["PUG", "PUZ", "PUD", "PATJ", "PMUD"]:
                layersColumnsFailed: dict[str, dict[str, list[int]]] = {}
                layersColumnsNames: dict[str, dict[str, dict[str, str]]] = json.loads(rule["valoare_regula"])

                for layer, columnLayers in layersColumnsNames.items():
                    time.sleep(self.loopLimit)

                    gpkgLayer: ogr.Layer = documentation_gpkg.GetLayerByName(layer)
                    gpkgLayerDefn: ogr.FeatureDefn = gpkgLayer.GetLayerDefn()

                    for column, layerColumnToVerify in columnLayers.items():
                        time.sleep(self.loopLimit)

                        sourceFieldIdx: int = gpkgLayerDefn.GetFieldIndex(column)
                        if sourceFieldIdx == -1:
                            continue

                        gpkgLayer.ResetReading()
                        codesToCheck: set[str] = set()
                        for feature in gpkgLayer:
                            time.sleep(self.loopLimit)
                            value = feature.GetField(sourceFieldIdx)
                            if value is not None:
                                codesToCheck.add(str(value).strip())

                        for layerToVerify, columnToVerify in layerColumnToVerify.items():
                            time.sleep(self.loopLimit)

                            gpkgLayerToCheck: ogr.Layer = documentation_gpkg.GetLayerByName(layerToVerify)
                            gpkgLayerToCheckDefn: ogr.FeatureDefn = gpkgLayerToCheck.GetLayerDefn()

                            targetFieldIdx: int = gpkgLayerToCheckDefn.GetFieldIndex(columnToVerify)
                            if targetFieldIdx == -1:
                                continue

                            gpkgLayerToCheck.ResetReading()
                            failedIds: set[int] = set()
                            for feature in gpkgLayerToCheck:
                                time.sleep(self.loopLimit)
                                if len(failedIds) >= 100:
                                    break
                                fid: int = feature.GetFID()
                                value = feature.GetField(targetFieldIdx)
                                if value is None or str(value).strip() not in codesToCheck:
                                    failedIds.add(fid)

                            if failedIds:
                                if layerToVerify not in layersColumnsFailed:
                                    layersColumnsFailed[layerToVerify] = {}
                                layersColumnsFailed[layerToVerify][columnToVerify] = sorted(failedIds)

            if layersColumnsFailed:
                self.rulesWriter.validation_fail(
                    rule=rule,
                    verify=f"Verificati coloanele straturilor din fisierului GPKG sa fie corelate corect: {layersColumnsFailed}")
                return int(rule['tip_alerta_id']) != 1
            else:
                self.rulesWriter.validation_pass(rule=rule)
                return True

        except Exception:
            traceBack = traceback.format_exc()
            self.logger.error(
                f"[{self.__class__.__name__} - {self.zonal_code_correlation.__name__}] "
                f"Failed to verify if layers columns code data is correlated correct.\n{traceBack}")
            self.rulesWriter.validation_error(rule=rule)
            return int(rule['tip_alerta_id']) != 1

    # Rule type 27
    def coordonate_system(self,
            rule: dict[str, str],
            documentation_gpkg: gdal.Dataset,
            plan_type: Literal["PUG", "PUZ", "PUD", "PATJ", "PMUD"]) -> bool:
        """Verifies if the coordinate system is the right one based on OMDLPA 904."""
        try:
            if plan_type in ["PUG", "PUZ", "PUD", "PATJ", "PMUD"]:
                gpkgDocumentationLayer: ogr.Layer = documentation_gpkg.GetLayerByName(rule['formula_regula'])
                spatialRef: osr.SpatialReference = gpkgDocumentationLayer.GetSpatialRef()
                epsg = spatialRef.GetAuthorityCode(None)
                if epsg:
                    crs = f"EPSG:{epsg}"

                if not rule['valoare_regula'] == crs:
                    self.rulesWriter.validation_fail(rule=rule)
                    return int(rule['tip_alerta_id']) != 1
                else:
                    self.rulesWriter.validation_pass(rule=rule)
                    return True

        except Exception:
            traceBack = traceback.format_exc()
            self.logger.error(
                f"[{self.__class__.__name__} - {self.coordonate_system.__name__}] "
                f"Failed to verify if coordonate system is correct.\n{traceBack}")
            self.rulesWriter.validation_error(rule=rule)
            return int(rule['tip_alerta_id']) != 1

    # Rule type 29
    def geoms_values(self,
            rule: dict[str, str],
            documentation_gpkg: gdal.Dataset,
            plan_type: Literal["PUG", "PUZ", "PUD", "PATJ", "PMUD"]) -> bool:
        """Verifies if the geometries of the layers exist and are not null."""
        try:
            if plan_type in ["PUG", "PUZ", "PUD", "PATJ", "PMUD"]:
                failedLayers: dict[str, list[int]] = {}
                layersToCheck: list[str] = [l.strip() for l in rule["valoare_regula"].split(",")]
                layersNoData: list[str] = []

                for layer in layersToCheck:
                    time.sleep(self.loopLimit)

                    gpkgDocumentationLayer: ogr.Layer = documentation_gpkg.GetLayerByName(layer)
                    if gpkgDocumentationLayer.GetFeatureCount() == 0:
                        layersNoData.append(layer)
                        continue

                    gpkgDocumentationLayer.ResetReading()
                    nullGeomFids: set[int] = set()
                    for feature in gpkgDocumentationLayer:
                        time.sleep(self.loopLimit)
                        if len(nullGeomFids) >= 100:
                            break
                        if feature.GetGeometryRef() is None:
                            nullGeomFids.add(feature.GetFID())

                    if nullGeomFids:
                        failedLayers[layer] = sorted(nullGeomFids)

            if layersNoData:
                self.rulesWriter.validation_fail(
                    rule=rule,
                    verify=f"Verificati straturile fisierului GPKG sa contina date: {layersNoData}")
                return int(rule['tip_alerta_id']) != 1
            elif failedLayers:
                self.rulesWriter.validation_fail(
                    rule=rule,
                    verify=f"Verificati straturile fisierului GPKG sa nu contina geometrii nule: {failedLayers}")
                return int(rule['tip_alerta_id']) != 1
            else:
                self.rulesWriter.validation_pass(rule=rule)
                return True

        except Exception:
            traceBack = traceback.format_exc()
            self.logger.error(
                f"[{self.__class__.__name__} - {self.geoms_values.__name__}] "
                f"Failed to verify if the geoms have data and are not NULL.\n{traceBack}")
            self.rulesWriter.validation_error(rule=rule)
            return int(rule['tip_alerta_id']) != 1

    # Rule type 31
    def geoms_valid(self,
            rule: dict[str, str],
            documentation_gpkg: gdal.Dataset,
            plan_type: Literal["PUG", "PUZ", "PUD", "PATJ", "PMUD"]) -> bool:
        """Verifies if the geometries of the layers are valid and have no donut polygons."""
        try:
            if plan_type in ["PUG", "PUZ", "PUD", "PATJ", "PMUD"]:
                failedLayers: dict[str, list[int]] = {}
                # donutLayers: dict[str, list[int]] = {}
                layersToCheck: list[str] = [l.strip() for l in rule["valoare_regula"].split(",")]
                layersNoData: list[str] = []

                for layer in layersToCheck:
                    time.sleep(self.loopLimit)

                    gpkgDocumentationLayer: ogr.Layer = documentation_gpkg.GetLayerByName(layer)
                    if gpkgDocumentationLayer.GetFeatureCount() == 0:
                        layersNoData.append(layer)
                        continue

                    # --- Geometry validity ---
                    gpkgDocumentationLayer.ResetReading()
                    invalidGeomFids: set[int] = set()
                    for feature in gpkgDocumentationLayer:
                        time.sleep(self.loopLimit)
                        if len(invalidGeomFids) >= 100:
                            break
                        geometry: ogr.Geometry = feature.GetGeometryRef()
                        if geometry is None or not geometry.IsValid():
                            invalidGeomFids.add(feature.GetFID())

                    if invalidGeomFids:
                        failedLayers[layer] = sorted(invalidGeomFids)

                    # --- Topology: donut polygons (interior rings) --- removeeeeee
                    # gpkgDocumentationLayer.ResetReading()
                    # donutFids: set[int] = set()
                    # for feature in gpkgDocumentationLayer:
                    #     time.sleep(self.loopLimit)
                    #     if len(donutFids) >= 100:
                    #         break
                    #     geometry: ogr.Geometry = feature.GetGeometryRef()
                    #     if geometry is None:
                    #         continue
                    #     geomType: int = geometry.GetGeometryType()
                    #     if geomType in (ogr.wkbPolygon, ogr.wkbPolygon25D, ogr.wkbPolygonM, ogr.wkbPolygonZM):
                    #         if geometry.GetGeometryCount() > 1:
                    #             donutFids.add(feature.GetFID())
                    #     elif geomType in (ogr.wkbMultiPolygon, ogr.wkbMultiPolygon25D, ogr.wkbMultiPolygonM, ogr.wkbMultiPolygonZM):
                    #         for i in range(geometry.GetGeometryCount()):
                    #             if geometry.GetGeometryRef(i).GetGeometryCount() > 1:
                    #                 donutFids.add(feature.GetFID())
                    #                 break

                    # if donutFids:
                    #     donutLayers[layer] = sorted(donutFids)

            if layersNoData:
                self.rulesWriter.validation_fail(
                    rule=rule,
                    verify=f"Verificati straturile fisierului GPKG sa contina date: {layersNoData}")
                return int(rule['tip_alerta_id']) != 1
            elif failedLayers:
                self.rulesWriter.validation_fail(
                    rule=rule,
                    verify=f"Verificati straturile fisierului GPKG sa nu contina geometrii invalide: {failedLayers}")
                return int(rule['tip_alerta_id']) != 1
            # elif donutLayers:
            #     self.rulesWriter.validation_fail(
            #         rule=rule,
            #         verify=f"Verificati straturile fisierului GPKG sa nu contina poligoane cu goluri interioare (donut): {donutLayers}")
            #     return int(rule['tip_alerta_id']) != 1
            else:
                self.rulesWriter.validation_pass(rule=rule)
                return True

        except Exception:
            traceBack = traceback.format_exc()
            self.logger.error(
                f"[{self.__class__.__name__} - {self.geoms_valid.__name__}] "
                f"Failed to verify if the geoms are valid.\n{traceBack}")
            self.rulesWriter.validation_error(rule=rule)
            return int(rule['tip_alerta_id']) != 1

    # Rule type 32
    def administrative_limit(self,
            rule: dict[str, str],
            documentation_gpkg: gdal.Dataset,
            uat_limit: UatLimitGet,
            plan_type: Literal["PUG", "PUZ", "PUD", "PATJ", "PMUD"]) -> bool:
        """Verifies if the PlanSpatial is in the administrative limit."""
        try:
            if plan_type in ["PUG", "PUZ", "PUD", "PATJ", "PMUD"]:
                sirutaColumnName: str = rule["valoare_regula"]
                layerName: str = rule["formula_regula"]

                gpkgDocumentationLayer: ogr.Layer = documentation_gpkg.GetLayerByName(layerName)
                gpkgLayerDefn: ogr.FeatureDefn = gpkgDocumentationLayer.GetLayerDefn()
                fieldIndex: int = gpkgLayerDefn.GetFieldIndex(sirutaColumnName)

                gpkgDocumentationLayer.ResetReading()
                sirutaValues: list[str] = []
                for feature in gpkgDocumentationLayer:
                    time.sleep(self.loopLimit)
                    if fieldIndex >= 0 and feature.IsFieldSet(fieldIndex) and not feature.IsFieldNull(fieldIndex):
                        sirutaValue = feature.GetField(fieldIndex)
                        if sirutaValue is not None:
                            sirutaValues.append(str(sirutaValue).strip())

                if len(sirutaValues) == 0:
                    self.rulesWriter.validation_fail(rule=rule, verify=f"Stratul {layerName} nu contine siruta")
                    return int(rule['tip_alerta_id']) != 1
                elif len(sirutaValues) > 1:
                    self.rulesWriter.validation_fail(rule=rule, verify=f"Stratul {layerName} contine mai multe inregistrari pentru siruta")
                    return int(rule['tip_alerta_id']) != 1
                else:
                    sirutaCode: str = sirutaValues[0]
                    uatGeomData = uat_limit(siruta=sirutaCode)
                    geomJson: str = json.dumps(uatGeomData['geometry'])
                    geometryVerification: ogr.Geometry = ogr.CreateGeometryFromJson(geomJson)

                    if geometryVerification is None:
                        self.rulesWriter.validation_fail(rule=rule, verify=f"Geometria UAT pentru siruta {sirutaCode} nu a putut fi creata")
                        return int(rule['tip_alerta_id']) != 1

                    bufferedVerification: ogr.Geometry = geometryVerification.Buffer(10)

                    gpkgDocumentationLayer.ResetReading()
                    failedFids: list[int] = []
                    for feature in gpkgDocumentationLayer:
                        time.sleep(self.loopLimit)
                        fid: int = feature.GetFID()
                        geom: ogr.Geometry = feature.GetGeometryRef()
                        if geom is None or not geom.Within(bufferedVerification):
                            failedFids.append(fid)

                    if failedFids:
                        self.rulesWriter.validation_fail(rule=rule, verify=f"{rule['mesaj_modificare']} - FID-uri in afara limitei UAT: {failedFids[:100]}")
                        return int(rule['tip_alerta_id']) != 1
                    else:
                        self.rulesWriter.validation_pass(rule=rule)
                        return True

        except Exception:
            traceBack = traceback.format_exc()
            self.logger.error(
                f"[{self.__class__.__name__} - {self.administrative_limit.__name__}] "
                f"Failed to verify if the plan spatial is the administrative plan.\n{traceBack}")
            self.rulesWriter.validation_error(rule=rule)
            return int(rule['tip_alerta_id']) != 1

    # Rule type 33
    def geoms_in_plan(self,
            rule: dict[str, str],
            documentation_gpkg: gdal.Dataset,
            plan_type: Literal["PUG", "PUZ", "PUD", "PATJ", "PMUD"]) -> bool:
        """Verifies if the geometries of the layers are in the PlanSpatial."""
        try:
            if plan_type in ["PUG", "PUZ", "PUD", "PATJ", "PMUD"]:
                layersNameToBeIn: str = rule["formula_regula"]
                layerNamesToCheck: list[str] = [l.strip() for l in rule["valoare_regula"].split(",")]
                layersGeomsFailed: dict[str, list[int]] = {}

                layerToBeIn: ogr.Layer = documentation_gpkg.GetLayerByName(layersNameToBeIn)

                # Build the union geometry once, outside the per-layer loop
                unionGeom: ogr.Geometry | None = None
                unionGeomBuffered: ogr.Geometry | None = None

                if layerToBeIn is None:
                    self.rulesWriter.validation_fail(rule=rule, verify=f"Stratul {layersNameToBeIn} nu exista")
                    return int(rule['tip_alerta_id']) != 1

                layerToBeIn.ResetReading()
                for feature in layerToBeIn:
                    time.sleep(self.loopLimit)
                    geom = feature.GetGeometryRef()
                    if geom:
                        unionGeom = geom.Clone() if unionGeom is None else unionGeom.Union(geom)

                if unionGeom is None:
                    self.rulesWriter.validation_fail(rule=rule, verify=f"Stratul {layersNameToBeIn} nu contine geometrii")
                    return int(rule['tip_alerta_id']) != 1

                unionGeomBuffered = unionGeom.Buffer(10)

                for layer in layerNamesToCheck:
                    time.sleep(self.loopLimit)
                    geomsOutside: list[int] = []

                    layerToCheck: ogr.Layer = documentation_gpkg.GetLayerByName(layer)
                    if layerToCheck is None:
                        self.rulesWriter.validation_fail(rule=rule, verify=f"Stratul {layer} nu exista")
                        return int(rule['tip_alerta_id']) != 1

                    layerToCheck.ResetReading()
                    for feature in layerToCheck:
                        time.sleep(self.loopLimit)
                        fid = feature.GetFID()
                        geom: ogr.Geometry = feature.GetGeometryRef()
                        if geom and not geom.Within(unionGeomBuffered):
                            geomsOutside.append(fid)

                    if geomsOutside:
                        layersGeomsFailed[layer] = geomsOutside[:100]

                if layersGeomsFailed:
                    self.rulesWriter.validation_fail(rule=rule, verify=layersGeomsFailed)
                    return int(rule['tip_alerta_id']) != 1
                else:
                    self.rulesWriter.validation_pass(rule=rule)
                    return True

        except Exception:
            traceBack = traceback.format_exc()
            self.logger.error(
                f"[{self.__class__.__name__} - {self.geoms_in_plan.__name__}] "
                f"Failed to verify if the geoms of the other layers are inside the PlanSpatial.\n{traceBack}")
            self.rulesWriter.validation_error(rule=rule)
            return int(rule['tip_alerta_id']) != 1

    # Rule type 34
    def geoms_cover_plan(self,
            rule: dict[str, str],
            documentation_gpkg: gdal.Dataset,
            plan_type: Literal["PUG", "PUZ", "PUD", "PATJ", "PMUD"]) -> bool:
        """Verifies if the geometries of the layers cover the PlanSpatial."""
        try:
            if plan_type in ["PUG", "PUZ", "PUD", "PATJ", "PMUD"]:
                layerNameToBeCovered: str = rule["formula_regula"]
                layersNameToCover: list[str] = [l.strip() for l in rule["valoare_regula"].split(",")]

                layerToBeCovered: ogr.Layer = documentation_gpkg.GetLayerByName(layerNameToBeCovered)
                if not layerToBeCovered:
                    self.rulesWriter.validation_fail(rule=rule, verify=f"Stratul {layerNameToBeCovered} nu exista")
                    return int(rule['tip_alerta_id']) != 1

                areaToBeCovered: float = 0.0
                layerToBeCovered.ResetReading()
                for feature in layerToBeCovered:
                    time.sleep(self.loopLimit)
                    geom: ogr.Geometry = feature.GetGeometryRef()
                    if geom:
                        areaToBeCovered += geom.GetArea()

                layersFail: list[str] = []
                margin: float = 50.0

                for layer in layersNameToCover:
                    time.sleep(self.loopLimit)

                    layerToCover: ogr.Layer = documentation_gpkg.GetLayerByName(layer)
                    if not layerToCover:
                        self.rulesWriter.validation_fail(rule=rule, verify=f"Stratul {layer} nu exista")
                        return int(rule['tip_alerta_id']) != 1

                    layerToCover.ResetReading()
                    areaCover: float = 0.0
                    for feature in layerToCover:
                        time.sleep(self.loopLimit)
                        geom: ogr.Geometry = feature.GetGeometryRef()
                        if geom:
                            areaCover += geom.GetArea()

                    if abs(areaCover - areaToBeCovered) >= margin:
                        layersFail.append(layer)

            if layersFail:
                self.rulesWriter.validation_fail(
                    rule=rule,
                    verify=f"Verificati straturile care nu acopera stratul {layerNameToBeCovered}: {layersFail}")
                return int(rule['tip_alerta_id']) != 1
            else:
                self.rulesWriter.validation_pass(rule=rule)
                return True

        except Exception:
            traceBack = traceback.format_exc()
            self.logger.error(
                f"[{self.__class__.__name__} - {self.geoms_cover_plan.__name__}] "
                f"Failed to verify if the geoms of the other layers cover the PlanSpatial.\n{traceBack}")
            self.rulesWriter.validation_error(rule=rule)
            return int(rule['tip_alerta_id']) != 1

    # Rule type 35
    def geoms_overlap(self,
            rule: dict[str, str],
            documentation_gpkg: gdal.Dataset,
            plan_type: Literal["PUG", "PUZ", "PUD", "PATJ", "PMUD"]) -> bool:
        """Verifies if the geometries of the layers overlap."""
        try:
            if plan_type in ["PUG", "PUZ", "PUD", "PATJ", "PMUD"]:
                layers_to_check: list[str] = [l.strip() for l in rule["valoare_regula"].split(",")]
                failed_layers: dict[str, list[tuple[int, int]]] = {}

                for layer_name in layers_to_check:
                    time.sleep(self.loopLimit)

                    layer: ogr.Layer = documentation_gpkg.GetLayerByName(layer_name)
                    if layer is None:
                        continue

                    shrunk_by_fid: dict[int, ogr.Geometry] = {}

                    layer.ResetReading()
                    for feature in layer:
                        time.sleep(self.loopLimit)
                        fid: int = feature.GetFID()
                        geom: ogr.Geometry = feature.GetGeometryRef()

                        if geom is None or geom.IsEmpty():
                            continue
                        if not geom.IsValid():
                            geom = geom.Buffer(0)
                            if geom is None or geom.IsEmpty():
                                self.logger.debug(f"FID {fid}: Geometry invalid and unrepairable, skipping")
                                continue

                        shrunk: ogr.Geometry = geom.Buffer(-1.0)
                        if shrunk is None or shrunk.IsEmpty():
                            self.logger.debug(f"FID {fid}: Geometry too small to shrink by 1m, skipping overlap check")
                            continue

                        shrunk_by_fid[fid] = shrunk.Clone()

                    if not shrunk_by_fid:
                        continue

                    mem_driver: ogr.Driver = ogr.GetDriverByName('MEM')
                    index_ds: ogr.DataSource = mem_driver.CreateDataSource('temp')
                    srs = layer.GetSpatialRef()
                    idx_layer: ogr.Layer = index_ds.CreateLayer('index', srs, ogr.wkbPolygon)
                    idx_layer.CreateField(ogr.FieldDefn('fid', ogr.OFTInteger64))
                    feat_defn: ogr.FeatureDefn = idx_layer.GetLayerDefn()

                    for fid, shrunk in shrunk_by_fid.items():
                        idx_feature: ogr.Feature = ogr.Feature(feat_defn)
                        idx_feature.SetGeometry(shrunk)
                        idx_feature.SetField('fid', fid)
                        idx_layer.CreateFeature(idx_feature)

                    layer_failed: list[tuple[int, int]] = []
                    checked_pairs: set[tuple[int, int]] = set()

                    for fid1, geom1 in shrunk_by_fid.items():
                        if len(layer_failed) >= 100:
                            break

                        time.sleep(self.loopLimit)
                        env = geom1.GetEnvelope()

                        idx_layer.SetSpatialFilterRect(env[0], env[2], env[1], env[3])
                        idx_layer.ResetReading()

                        for idx_feature in idx_layer:
                            time.sleep(self.loopLimit)
                            fid2: int = idx_feature.GetField('fid')
                            if fid2 == fid1:
                                continue

                            pair: tuple[int, int] = (min(fid1, fid2), max(fid1, fid2))
                            if pair in checked_pairs:
                                continue
                            checked_pairs.add(pair)

                            geom2: ogr.Geometry = shrunk_by_fid.get(fid2)
                            if geom2 is None:
                                continue

                            if geom1.Intersects(geom2) and not geom1.Touches(geom2):
                                layer_failed.append(pair)
                                if len(layer_failed) >= 100:
                                    break

                        idx_layer.SetSpatialFilter(None)

                    if layer_failed:
                        failed_layers[layer_name] = layer_failed

                    shrunk_by_fid.clear()
                    index_ds = None

            if failed_layers:
                self.rulesWriter.validation_fail(
                    rule=rule,
                    verify=f"Verificati geometriile din straturile fisierului GPKG sa nu se suprapuna: {failed_layers}")
                return int(rule['tip_alerta_id']) != 1
            else:
                self.rulesWriter.validation_pass(rule=rule)
                return True

        except Exception:
            traceBack = traceback.format_exc()
            self.logger.error(
                f"[{self.__class__.__name__} - {self.geoms_overlap.__name__}] "
                f"Failed to verify if the geoms overlap.\n{traceBack}")
            self.rulesWriter.validation_error(rule=rule)
            return int(rule['tip_alerta_id']) != 1

    # Rule type 36
    def geoms_sliver_polygons(self,
            rule: dict[str, str],
            documentation_gpkg: gdal.Dataset,
            plan_type: Literal["PUG", "PUZ", "PUD", "PATJ", "PMUD"]) -> bool:
        """Verifies if the geometries of the layers are sliver polygons."""
        try:
            _POLYGON_TYPES = frozenset({ogr.wkbPolygon, ogr.wkbMultiPolygon})
            _AREA_THRESHOLD = 1e-6
            _ASPECT_RATIO_THRESHOLD = 10
            _COMPACTNESS_THRESHOLD = 1000

            if plan_type in ("PUG", "PUZ", "PUD", "PATJ", "PMUD"):
                layersNameToCheck: list[str] = rule["valoare_regula"].split(",")
                failedLayers: dict[str, list[int]] = {}

                for layer in layersNameToCheck:
                    failedGeoms: list[int] = []
                    time.sleep(self.loopLimit)
                    layerToCheck: ogr.Layer = documentation_gpkg.GetLayerByName(layer)

                    for feature in layerToCheck:
                        time.sleep(self.loopLimit)
                        geom: ogr.Geometry = feature.GetGeometryRef()

                        if geom.GetGeometryType() not in _POLYGON_TYPES:
                            continue

                        area = geom.GetArea()
                        if area < _AREA_THRESHOLD:
                            failedGeoms.append(feature.GetFID())
                            continue

                        min_x, max_x, min_y, max_y = geom.GetEnvelope()
                        w = max_x - min_x
                        h = max_y - min_y
                        aspect_ratio = max(w, h) / (min(w, h) or 1)
                        if aspect_ratio > _ASPECT_RATIO_THRESHOLD:
                            failedGeoms.append(feature.GetFID())
                            continue

                        perimeter = geom.Boundary().Length()
                        if (perimeter * perimeter) / area > _COMPACTNESS_THRESHOLD:
                            failedGeoms.append(feature.GetFID())

                    if failedGeoms:
                        failedLayers[layer] = failedGeoms

                if failedLayers:
                    self.rulesWriter.validation_fail(rule=rule, verify=failedLayers)
                    return int(rule["tip_alerta_id"]) != 1

                self.rulesWriter.validation_pass(rule=rule)
                return True

        except Exception:
            traceBack = traceback.format_exc()
            self.logger.error(
                f"[{self.__class__.__name__} - {self.geoms_sliver_polygons.__name__}] "
                f"Failed to verify if the geoms are sliver polygons.\n{traceBack}")
            self.rulesWriter.validation_error(rule=rule)
            return int(rule["tip_alerta_id"]) != 1

    # Rule type 37
    def unique_codes(self,
            rule: dict[str, str],
            documentation_gpkg: gdal.Dataset,
            plan_type: Literal["PUG", "PUZ", "PUD", "PATJ", "PMUD"]) -> bool:
        """Verifies if the codes from the layers are unique."""
        try:
            if plan_type in ["PUG", "PUZ", "PUD", "PATJ", "PMUD"]:
                failedLayerColumnValues: dict[str, dict[str, list[str]]] = {}
                layersColumns: dict[str, list[str]] = json.loads(rule["valoare_regula"])

                for layer, columns in layersColumns.items():
                    gpkgLayer: ogr.Layer = documentation_gpkg.GetLayerByName(layer.strip())
                    if gpkgLayer.GetFeatureCount() == 0:
                        continue

                    gpkgLayerDefn: ogr.FeatureDefn = gpkgLayer.GetLayerDefn()

                    for column in columns:
                        time.sleep(self.loopLimit)

                        fieldIndex = gpkgLayerDefn.GetFieldIndex(column.strip())
                        if fieldIndex == -1:
                            continue

                        gpkgLayer.ResetReading()
                        # Use a set for O(1) duplicate detection instead of a list
                        seen: set[str] = set()
                        columnCodWrong: list[str] = []

                        for feature in gpkgLayer:
                            time.sleep(self.loopLimit)
                            value: str = feature.GetField(fieldIndex)
                            if value in seen:
                                columnCodWrong.append(value)
                            else:
                                seen.add(value)

                        if columnCodWrong:
                            failedLayerColumnValues[layer] = {column: columnCodWrong[:100]}

                if failedLayerColumnValues:
                    self.rulesWriter.validation_fail(rule=rule, verify=f"Verificati codurile din coloanele straturilor sa fie unice: {failedLayerColumnValues}")
                    return int(rule['tip_alerta_id']) != 1
                else:
                    self.rulesWriter.validation_pass(rule=rule)
                    return True

        except Exception:
            traceBack = traceback.format_exc()
            self.logger.error(
                f"[{self.__class__.__name__} - {self.unique_codes.__name__}] "
                f"Failed to verify if the zonal codes are unique.\n{traceBack}")
            self.rulesWriter.validation_error(rule=rule)
            return int(rule['tip_alerta_id']) != 1

    # Rule type 38
    def cod_type_equal(self,
            rule: dict[str, str],
            documentation_gpkg: gdal.Dataset,
            plan_type: Literal["PUG", "PUZ", "PUD", "PATJ", "PMUD"]) -> bool:
        """Verifies if the codes and types from the layers are not duplicated or equal."""
        try:
            if plan_type in ["PUG", "PUZ", "PUD", "PATJ", "PMUD"]:
                failedLayerColumnValues: dict[str, list[int]] = {}
                layersColumns: dict[str, dict[str, str]] = json.loads(rule["valoare_regula"])

                for layer, columns in layersColumns.items():
                    time.sleep(self.loopLimit)

                    gpkgLayer: ogr.Layer = documentation_gpkg.GetLayerByName(layer)
                    gpkgLayerDefn: ogr.FeatureDefn = gpkgLayer.GetLayerDefn()

                    for codColumn, typeColumn in columns.items():
                        time.sleep(self.loopLimit)

                        # Resolve field indices once from the layer definition, not per feature
                        fieldIdCod = gpkgLayerDefn.GetFieldIndex(codColumn)
                        fieldIdType = gpkgLayerDefn.GetFieldIndex(typeColumn)

                        columnFailed: set[int] = set()
                        gpkgLayer.ResetReading()

                        for feature in gpkgLayer:
                            time.sleep(self.loopLimit)
                            fid = feature.GetFID()

                            codValue = None
                            typeValue = None

                            if fieldIdCod >= 0 and feature.IsFieldSet(fieldIdCod) and not feature.IsFieldNull(fieldIdCod):
                                codValue = feature.GetField(fieldIdCod)
                            else:
                                columnFailed.add(fid)

                            if fieldIdType >= 0 and feature.IsFieldSet(fieldIdType) and not feature.IsFieldNull(fieldIdType):
                                typeValue = feature.GetField(fieldIdType)
                            else:
                                columnFailed.add(fid)

                            if codValue == typeValue:
                                columnFailed.add(fid)

                        if columnFailed:
                            failedLayerColumnValues[layer] = sorted(columnFailed)[:100]

                if failedLayerColumnValues:
                    self.rulesWriter.validation_fail(rule=rule, verify=f"Verificati codurile si tipurile straturilor sa nu fie duplicate: {failedLayerColumnValues}")
                    return int(rule['tip_alerta_id']) != 1
                else:
                    self.rulesWriter.validation_pass(rule=rule)
                    return True

        except Exception:
            traceBack = traceback.format_exc()
            self.logger.error(
                f"[{self.__class__.__name__} - {self.cod_type_equal.__name__}] "
                f"Failed to verify if the zonal codes and types are not the same.\n{traceBack}")
            self.rulesWriter.validation_error(rule=rule)
            return int(rule['tip_alerta_id']) != 1

    # Rule Type 39
    def cod_type_correlation(self,
            rule: dict[str, str],
            documentation_gpkg: gdal.Dataset,
            template_metadata: dict[str, list[str] | dict[str, dict[str, str]] | dict[str, str]],
            plan_type: Literal["PUG", "PUZ", "PUD", "PATJ", "PMUD"]) -> bool:
        """Verifies if the codes and types from the layers are correlated based on OMDLPA 904."""
        try:
            if plan_type in ["PUG", "PUZ", "PUD", "PATJ", "PMUD"]:
                failedLayerColumnValues: dict[str, list[int]] = {}
                layersColumns: dict[str, dict[str, str]] = json.loads(rule["valoare_regula"])

                for layer, columns in layersColumns.items():
                    time.sleep(self.loopLimit)

                    gpkgLayer: ogr.Layer = documentation_gpkg.GetLayerByName(layer)
                    gpkgLayerDefn: ogr.FeatureDefn = gpkgLayer.GetLayerDefn()

                    for codColumn, typeColumn in columns.items():
                        time.sleep(self.loopLimit)

                        # Resolve field indices once from the layer definition, not per feature
                        fieldIdCod = gpkgLayerDefn.GetFieldIndex(codColumn)
                        fieldIdType = gpkgLayerDefn.GetFieldIndex(typeColumn)

                        columnFailed: set[int] = set()
                        gpkgLayer.ResetReading()

                        for feature in gpkgLayer:
                            time.sleep(self.loopLimit)
                            fid = feature.GetFID()

                            codValue = None
                            typeValue = None

                            if fieldIdCod >= 0 and feature.IsFieldSet(fieldIdCod) and not feature.IsFieldNull(fieldIdCod):
                                codValue = feature.GetField(fieldIdCod)
                            else:
                                columnFailed.add(fid)

                            if fieldIdType >= 0 and feature.IsFieldSet(fieldIdType) and not feature.IsFieldNull(fieldIdType):
                                typeValue = feature.GetField(fieldIdType)
                            else:
                                columnFailed.add(fid)

                            if codValue in template_metadata["Cod_Tip_Zona_ZF_ZRS"]:
                                if typeValue not in template_metadata["Cod_Tip_Zona_ZF_ZRS"].get(codValue, []):
                                    columnFailed.add(fid)
                            else:
                                columnFailed.add(fid)

                        if columnFailed:
                            failedLayerColumnValues[layer] = sorted(columnFailed)[:100]

                if failedLayerColumnValues:
                    self.rulesWriter.validation_fail(rule=rule, verify=f"Verificati codurile si tipurile straturilor sa fie corelate corect: {failedLayerColumnValues}")
                    return int(rule['tip_alerta_id']) != 1
                else:
                    self.rulesWriter.validation_pass(rule=rule)
                    return True

        except Exception:
            traceBack = traceback.format_exc()
            self.logger.error(
                f"[{self.__class__.__name__} - {self.cod_type_correlation.__name__}] "
                f"Failed to verify if the zonal codes and types are correlated.\n{traceBack}")
            self.rulesWriter.validation_error(rule=rule)
            return int(rule['tip_alerta_id']) != 1

    # Rule Type 40
    def temporal_dates_equal(self,
            rule: dict[str, str],
            documentation_gpkg: gdal.Dataset,
            plan_type: Literal["PUG", "PUZ", "PUD", "PATJ", "PMUD"]) -> bool:
        """Verifies if the temporal dates are the same in all the layers columns rows."""
        try:
            if plan_type in ["PUG", "PUZ", "PUD", "PATJ", "PMUD"]:
                failedLayerColumnValues: dict[str, dict[str, list[int]]] = {}
                layersColumns: dict[str, list[str]] = json.loads(rule["valoare_regula"])

                for layer, columns in layersColumns.items():
                    time.sleep(self.loopLimit)

                    gpkgLayer: ogr.Layer = documentation_gpkg.GetLayerByName(layer)
                    gpkgLayerDefn: ogr.FeatureDefn = gpkgLayer.GetLayerDefn()

                    for column in columns:
                        time.sleep(self.loopLimit)

                        # Resolve field index once from the layer definition, not per feature
                        fieldIdDate = gpkgLayerDefn.GetFieldIndex(column)
                        if fieldIdDate == -1:
                            continue

                        columnFailed: list[int] = []
                        gpkgLayer.ResetReading()
                        # Store only the first valid date value for comparison
                        referenceDate = None

                        for feature in gpkgLayer:
                            time.sleep(self.loopLimit)
                            fid = feature.GetFID()

                            if feature.IsFieldSet(fieldIdDate) and not feature.IsFieldNull(fieldIdDate):
                                dateValue = feature.GetField(fieldIdDate)
                            else:
                                columnFailed.append(fid)
                                continue

                            if referenceDate is None:
                                referenceDate = dateValue
                            elif dateValue != referenceDate:
                                columnFailed.append(fid)

                        if columnFailed:
                            failedLayerColumnValues[layer] = {column: columnFailed[:100]}

                if failedLayerColumnValues:
                    self.rulesWriter.validation_fail(rule=rule, verify=f"Verificati datele temporale sa fie unice in straturile fisierului GPKG: {failedLayerColumnValues}")
                    return int(rule['tip_alerta_id']) != 1
                else:
                    self.rulesWriter.validation_pass(rule=rule)
                    return True

        except Exception:
            traceBack = traceback.format_exc()
            self.logger.error(
                f"[{self.__class__.__name__} - {self.temporal_dates_equal.__name__}] "
                f"Failed to verify if the temporal code are the same in the date columns.\n{traceBack}")
            self.rulesWriter.validation_error(rule=rule)
            return int(rule['tip_alerta_id']) != 1

    # Rule Type 41
    def coordonates_types(self,
            rule: dict[str, str],
            documentation_gpkg: gdal.Dataset,
            plan_type: Literal["PUG", "PUZ", "PUD", "PATJ", "PMUD"]) -> bool:
        """Verifies if the geometries from the layers are 2D."""
        try:
            if plan_type in ["PUG", "PUZ", "PUD", "PATJ", "PMUD"]:
                failedLayerIds: dict[str, list[int]] = {}
                layersNames: list[str] = rule["valoare_regula"].split(",")

                for layer in layersNames:
                    time.sleep(self.loopLimit)

                    gpkgLayer: ogr.Layer = documentation_gpkg.GetLayerByName(layer)
                    if gpkgLayer is None:
                        continue

                    failedFids: list[int] = []
                    gpkgLayer.ResetReading()

                    for feature in gpkgLayer:
                        time.sleep(self.loopLimit)
                        fid = feature.GetFID()
                        geom: ogr.Geometry = feature.GetGeometryRef()
                        if geom is None or geom.GetCoordinateDimension() != 2:
                            failedFids.append(fid)

                    if failedFids:
                        failedLayerIds[layer] = failedFids[:100]

                if failedLayerIds:
                    self.rulesWriter.validation_fail(rule=rule, verify=f"Verificati geometriile din straturile fisierului GPKG sa nu aiba coordonate de lungime (M) sau altitudine (Z): {failedLayerIds}")
                    return int(rule['tip_alerta_id']) != 1
                else:
                    self.rulesWriter.validation_pass(rule=rule)
                    return True

        except Exception:
            traceBack = traceback.format_exc()
            self.logger.error(
                f"[{self.__class__.__name__} - {self.coordonates_types.__name__}] "
                f"Failed to verify if the coordonate types are only longitude and latitude.\n{traceBack}")
            self.rulesWriter.validation_error(rule=rule)
            return int(rule['tip_alerta_id']) != 1

    # Rule Type 42
    def geom_area(self,
            rule: dict[str, str],
            documentation_gpkg: gdal.Dataset,
            plan_type: Literal["PUG", "PUZ", "PUD", "PATJ", "PMUD"]) -> bool:
        """Verifies if the geometries have the same area as the one specified in the layer columns."""
        _HECTARE_LAYERS = frozenset({"PlanSpatial", "LimitaIntravilanExistenta", "LimitaIntravilanPropusa"})
        _SQM_LAYERS = frozenset({"ZFExistenta", "ZFPropusa", "ZonaReglementareSuplimentara"})

        try:
            if plan_type in ["PUG", "PUZ", "PUD", "PATJ", "PMUD"]:
                failedLayerColumnValues: dict[str, list[int]] = {}
                layersColumns: dict[str, str] = json.loads(rule["valoare_regula"])

                for layer, column in layersColumns.items():
                    time.sleep(self.loopLimit)
                    layerStripped = layer.strip()
                    gpkglayer: ogr.Layer = documentation_gpkg.GetLayerByName(layerStripped)
                    gpkglayer.ResetReading()

                    # Determine conversion once per layer, not per feature
                    if layerStripped in _HECTARE_LAYERS:
                        conversion = 1 / 10000
                    elif layerStripped in _SQM_LAYERS:
                        conversion = 1.0
                    else:
                        # Layer not in any known group — skip to avoid uninitialized calculated_area
                        self.logger.warning(f"geom_area: layer '{layerStripped}' not in known area groups, skipping")
                        continue

                    indexFail: list[int] = []

                    for feature in gpkglayer:
                        time.sleep(self.loopLimit)
                        fid = feature.GetFID()

                        geom: ogr.Geometry = feature.GetGeometryRef()
                        if geom is None:
                            indexFail.append(fid)
                            continue

                        fieldIndex = feature.GetFieldIndex(column)
                        if fieldIndex < 0:
                            indexFail.append(fid)
                            continue

                        storedArea = feature.GetField(fieldIndex)
                        if storedArea is None:
                            indexFail.append(fid)
                            continue

                        calculated_area = round(geom.GetArea() * conversion, 2)
                        if abs(calculated_area - float(storedArea)) > 0.1:
                            indexFail.append(fid)

                    if indexFail:
                        failedLayerColumnValues[layer] = indexFail[:100]

                if failedLayerColumnValues:
                    self.rulesWriter.validation_fail(rule=rule, verify=f"Verificati aria specificata pentru geometriile din straturile fisierului GPKG sa fie corecta : {failedLayerColumnValues}")
                    return int(rule['tip_alerta_id']) != 1
                else:
                    self.rulesWriter.validation_pass(rule=rule)
                    return True

        except Exception:
            traceBack = traceback.format_exc()
            self.logger.error(
                f"[{self.__class__.__name__} - {self.geom_area.__name__}] "
                f"Failed to verify if the geom area is the same as the one specified.\n{traceBack}")
            self.rulesWriter.validation_error(rule=rule)
            return int(rule['tip_alerta_id']) != 1

    # Rule Type 43
    def geom_length(self,
            rule: dict[str, str],
            documentation_gpkg: gdal.Dataset,
            plan_type: Literal["PUG", "PUZ", "PUD", "PATJ", "PMUD"]) -> bool:
        """Verifies if the geometries have the same length as the one specified in the layer columns."""
        try:
            if plan_type in ["PUG", "PUZ", "PUD", "PATJ", "PMUD"]:
                failedLayerColumnValues: dict[str, list[int]] = {}
                layersColumns: dict[str, str] = json.loads(rule["valoare_regula"])

                for layer, column in layersColumns.items():
                    time.sleep(self.loopLimit)
                    gpkglayer: ogr.Layer = documentation_gpkg.GetLayerByName(layer.strip())
                    gpkglayer.ResetReading()

                    indexFail: list[int] = []

                    for feature in gpkglayer:
                        time.sleep(self.loopLimit)
                        fid = feature.GetFID()

                        geom: ogr.Geometry = feature.GetGeometryRef()
                        if geom is None:
                            indexFail.append(fid)
                            continue

                        fieldIndex = feature.GetFieldIndex(column)
                        if fieldIndex < 0:
                            indexFail.append(fid)
                            continue

                        storedLength = feature.GetField(fieldIndex)
                        if storedLength is None:
                            indexFail.append(fid)
                            continue

                        if abs(round(geom.Length(), 2) - float(storedLength)) > 0.1:
                            indexFail.append(fid)

                    if indexFail:
                        failedLayerColumnValues[layer] = indexFail[:100]

                if failedLayerColumnValues:
                    self.rulesWriter.validation_fail(rule=rule, verify=f"Verificati lungimea specificata pentru geometriile din straturile fisierului GPKG sa fie corecta : {failedLayerColumnValues}")
                    return int(rule['tip_alerta_id']) != 1
                else:
                    self.rulesWriter.validation_pass(rule=rule)
                    return True

        except Exception:
            traceBack = traceback.format_exc()
            self.logger.error(
                f"[{self.__class__.__name__} - {self.geom_length.__name__}] "
                f"Failed to verify if the geom length is the same as the one specified.\n{traceBack}")
            self.rulesWriter.validation_error(rule=rule)
            return int(rule['tip_alerta_id']) != 1

    # Rule Type 44
    def area_equal_to_planspatial(self,
            rule: dict[str, str],
            documentation_gpkg: gdal.Dataset,
            plan_type: Literal["PUG", "PUZ", "PUD", "PATJ", "PMUD"]) -> bool:
        """Verifies if the area from LimitaIntravilanPropusa is equal to that of the PlanSpatial."""
        try:
            if plan_type in ["PUG", "PUZ", "PUD", "PATJ", "PMUD"]:
                layersColumns: dict[str, str] = json.loads(rule["valoare_regula"])

                items = list(layersColumns.items())
                (planSpatial, areaPlanSpatial), (limitaIntravilanPropusa, areaLimitaIntravilanPropusa) = items

                planSpatialLayer: ogr.Layer = documentation_gpkg.GetLayerByName(planSpatial)
                planSpatialLayer.ResetReading()
                planSpatialFeatures = list(planSpatialLayer)

                if len(planSpatialFeatures) != 1:
                    self.rulesWriter.validation_fail(rule=rule, verify=f"Stratul {planSpatial} contine mai mult de o geometrie")
                    return int(rule['tip_alerta_id']) != 1

                planSpatialFeature: ogr.Feature = planSpatialFeatures[0]
                fieldIdx = planSpatialFeature.GetFieldIndex(areaPlanSpatial)
                planSpatialStoredArea = planSpatialFeature.GetField(fieldIdx)

                if planSpatialStoredArea is None:
                    self.rulesWriter.validation_fail(rule=rule, verify=f"Stratul {planSpatial} nu contine aria in coloana {areaPlanSpatial}")
                    return int(rule['tip_alerta_id']) != 1

                planSpatialTargetArea = float(planSpatialStoredArea)

                limitaIntravilanPropusaLayer: ogr.Layer = documentation_gpkg.GetLayerByName(limitaIntravilanPropusa)
                limitaIntravilanPropusaLayer.ResetReading()

                totalCalculatedArea = 0.0
                for feature in limitaIntravilanPropusaLayer:
                    time.sleep(self.loopLimit)
                    fieldIndex = feature.GetFieldIndex(areaLimitaIntravilanPropusa)
                    if fieldIndex < 0:
                        continue
                    if not feature.IsFieldSet(fieldIndex) or feature.IsFieldNull(fieldIndex):
                        continue
                    areaValue = feature.GetField(fieldIndex)
                    if areaValue is not None:
                        totalCalculatedArea += float(areaValue)

                withinTolerance = abs(totalCalculatedArea - planSpatialTargetArea) <= 0.1

            if not withinTolerance:
                self.rulesWriter.validation_fail(rule=rule, verify=f"Verificati ariile din stratul {limitaIntravilanPropusa} si aria din stratul {planSpatial} sa fie egale")
                return int(rule['tip_alerta_id']) != 1
            else:
                self.rulesWriter.validation_pass(rule=rule)
                return True

        except Exception:
            traceBack = traceback.format_exc()
            self.logger.error(
                f"[{self.__class__.__name__} - {self.area_equal_to_planspatial.__name__}] "
                f"Failed to verify if the total geom area is the same as the total geom area of PlanSpatial.\n{traceBack}")
            self.rulesWriter.validation_error(rule=rule)
            return int(rule['tip_alerta_id']) != 1

    # Rule Type 46
    def regulament_zones_codes_types(self,
            rule: dict[str, str],
            documentation_gpkg: gdal.Dataset,
            plan_type: Literal["PUG", "PUZ", "PUD", "PATJ", "PMUD"]) -> bool:
        """Verifies if the codes from the ZF, ZRS codes and types of the RLU and RLUD layers are the same as in the functional zones."""
        try:
            if plan_type in ["PUG", "PUZ", "PUD", "PATJ", "PMUD"]:
                failedFeatures: dict[str, list[int]] = {}
                ruleDataLayers: list[dict] = json.loads(rule["valoare_regula"])

                # Iterate all rules before deciding pass/fail — do NOT return inside the loop
                for ruleData in ruleDataLayers:
                    time.sleep(self.loopLimit)
                    targetLayerName: str = ruleData["layer"]
                    matchesFrom: dict[str, list[str]] = ruleData["matches_fields_from"]
                    validatedFields: list[str] = ruleData["validated_fields"]

                    sourceLayerName: str = list(matchesFrom.keys())[0]
                    sourceFields: list[str] = matchesFrom[sourceLayerName]

                    targetLayer: ogr.Layer = documentation_gpkg.GetLayerByName(targetLayerName)
                    sourceLayer: ogr.Layer = documentation_gpkg.GetLayerByName(sourceLayerName)

                    if targetLayer is None or sourceLayer is None:
                        raise ValueError(f"Layer not found: {targetLayerName} or {sourceLayerName}")

                    targetLookup: dict[str, str] = {}
                    targetLayer.ResetReading()
                    for targetFeature in targetLayer:
                        time.sleep(self.loopLimit)
                        keyIdx = targetFeature.GetFieldIndex(validatedFields[0])
                        valIdx = targetFeature.GetFieldIndex(validatedFields[1])
                        if keyIdx < 0 or valIdx < 0:
                            continue
                        keyVal = targetFeature.GetField(keyIdx)
                        valVal = targetFeature.GetField(valIdx)
                        if keyVal is not None and valVal is not None:
                            targetLookup[str(keyVal)] = str(valVal)

                    sourceLayer.ResetReading()
                    for sourceFeature in sourceLayer:
                        time.sleep(self.loopLimit)
                        sourceFid = sourceFeature.GetFID()

                        sourceKeyIdx = sourceFeature.GetFieldIndex(sourceFields[0])
                        sourceValIdx = sourceFeature.GetFieldIndex(sourceFields[1])

                        if sourceKeyIdx < 0 or sourceValIdx < 0:
                            failedFeatures.setdefault(sourceLayerName, []).append(sourceFid)
                            continue

                        sourceKey = sourceFeature.GetField(sourceKeyIdx)
                        sourceVal = sourceFeature.GetField(sourceValIdx)

                        if sourceKey is None or sourceVal is None:
                            failedFeatures.setdefault(sourceLayerName, []).append(sourceFid)
                            continue

                        sourceKeyStr = str(sourceKey)
                        sourceValStr = str(sourceVal)

                        if sourceKeyStr not in targetLookup or targetLookup[sourceKeyStr] != sourceValStr:
                            failedFeatures.setdefault(sourceLayerName, []).append(sourceFid)

                if failedFeatures:
                    self.rulesWriter.validation_fail(rule=rule, verify=f"Verificati codurile din RLU si RLUD sa fie corecte: {failedFeatures}")
                    return int(rule['tip_alerta_id']) != 1
                else:
                    self.rulesWriter.validation_pass(rule=rule)
                    return True

        except Exception:
            traceBack = traceback.format_exc()
            self.logger.error(
                f"[{self.__class__.__name__} - {self.regulament_zones_codes_types.__name__}] "
                f"Failed to verify if the codes and type of the regulament are the same as the zonal codes and types.\n{traceBack}")
            self.rulesWriter.validation_error(rule=rule)
            return int(rule['tip_alerta_id']) != 1

    # Rule Type 47
    def temporal_data_matches(self,
            rule: dict[str, str],
            documentation_gpkg: gdal.Dataset,
            plan_type: Literal["PUG", "PUZ", "PUD", "PATJ", "PMUD"]) -> bool:
        """Verifies if the temporal data from plan spatial matches with the other layers temporal data."""
        try:
            if plan_type in ["PUG", "PUZ", "PUD", "PATJ", "PMUD"]:
                failedFeatures: dict[str, list[int]] = {}
                rules: list[dict] = json.loads(rule["valoare_regula"])
                targetLayerCache: dict[str, ogr.Feature] = {}

                for validationRule in rules:
                    time.sleep(self.loopLimit)
                    targetLayerName: str = validationRule["layer"]
                    matchFieldsFrom: dict[str, str] = validationRule["match_fields_from"]
                    withField: str = validationRule["with_field"]

                    sourceLayerName: str = list(matchFieldsFrom.keys())[0]
                    sourceField: str = matchFieldsFrom[sourceLayerName]

                    if targetLayerName not in targetLayerCache:
                        targetLayer: ogr.Layer = documentation_gpkg.GetLayerByName(targetLayerName)
                        if targetLayer is None:
                            continue
                        targetLayer.ResetReading()
                        targetFeature = targetLayer.GetNextFeature()
                        if targetFeature is None:
                            continue
                        targetLayerCache[targetLayerName] = targetFeature

                    targetFeature = targetLayerCache[targetLayerName]
                    targetFieldIdx = targetFeature.GetFieldIndex(withField)
                    if targetFieldIdx < 0:
                        continue

                    targetValue = targetFeature.GetField(targetFieldIdx)
                    if targetValue is None:
                        continue

                    targetValueStr = str(targetValue)

                    sourceLayer: ogr.Layer = documentation_gpkg.GetLayerByName(sourceLayerName)
                    if sourceLayer is None:
                        continue

                    sourceLayer.ResetReading()
                    for sourceFeature in sourceLayer:
                        time.sleep(self.loopLimit)
                        sourceFid = sourceFeature.GetFID()
                        sourceFieldIdx = sourceFeature.GetFieldIndex(sourceField)

                        if sourceFieldIdx < 0:
                            failedFeatures.setdefault(sourceLayerName, []).append(sourceFid)
                            continue

                        sourceValue = sourceFeature.GetField(sourceFieldIdx)
                        if (str(sourceValue) if sourceValue is not None else "") != targetValueStr:
                            failedFeatures.setdefault(sourceLayerName, []).append(sourceFid)

                if failedFeatures:
                    self.rulesWriter.validation_fail(rule=rule, verify=f"Verificati datele temporale sa fie identice: {failedFeatures}")
                    return int(rule['tip_alerta_id']) != 1
                else:
                    self.rulesWriter.validation_pass(rule=rule)
                    return True

        except Exception:
            traceBack = traceback.format_exc()
            self.logger.error(
                f"[{self.__class__.__name__} - {self.temporal_data_matches.__name__}] "
                f"Failed to verify if the temporal dates from different layers match.\n{traceBack}")
            self.rulesWriter.validation_error(rule=rule)
            return int(rule['tip_alerta_id']) != 1

    # Rule Type 48
    def zones_temporal_dates(self,
            rule: dict[str, str],
            documentation_gpkg: gdal.Dataset,
            plan_type: Literal["PUG", "PUZ", "PUD", "PATJ", "PMUD"]) -> bool:
        """Verifies if the temporal data from the functional zones is not overlapped and in chronological order."""
        try:
            if plan_type in ["PUG", "PUZ", "PUD", "PATJ", "PMUD"]:
                rule_data: dict = json.loads(rule["valoare_regula"])
                failed_features: dict[str, list[int]] = {}

                for target_layer_name, rule_config in rule_data.items():
                    time.sleep(self.loopLimit)

                    match_fields_from = rule_config["match_fields_from"]
                    with_fields = rule_config["with_field"]

                    source_layer_name = list(match_fields_from.keys())[0]
                    source_fields = match_fields_from[source_layer_name]

                    target_layer = documentation_gpkg.GetLayerByName(target_layer_name)
                    source_layer = documentation_gpkg.GetLayerByName(source_layer_name)

                    if target_layer is None or source_layer is None:
                        continue

                    source_layer.ResetReading()
                    aprob_source_idx = source_layer.GetLayerDefn().GetFieldIndex(source_fields[0])
                    exp_source_idx = source_layer.GetLayerDefn().GetFieldIndex(source_fields[1])

                    if aprob_source_idx < 0 or exp_source_idx < 0:
                        continue

                    source_ranges: dict[int, tuple] = {}
                    for source_feature in source_layer:
                        time.sleep(self.loopLimit)
                        aprob_date = self._parse_zone_date(source_feature.GetField(aprob_source_idx))
                        exp_date = self._parse_zone_date(source_feature.GetField(exp_source_idx))
                        if aprob_date is not None and exp_date is not None:
                            source_ranges[source_feature.GetFID()] = (aprob_date, exp_date)

                    if not source_ranges:
                        continue

                    target_layer.ResetReading()
                    aprob_target_idx = target_layer.GetLayerDefn().GetFieldIndex(with_fields[0])
                    exp_target_idx = target_layer.GetLayerDefn().GetFieldIndex(with_fields[1])

                    if aprob_target_idx < 0 or exp_target_idx < 0:
                        continue

                    for target_feature in target_layer:
                        time.sleep(self.loopLimit)
                        target_fid = target_feature.GetFID()

                        target_aprob = self._parse_zone_date(target_feature.GetField(aprob_target_idx))
                        target_exp = self._parse_zone_date(target_feature.GetField(exp_target_idx))

                        if target_aprob is None or target_exp is None:
                            continue

                        if target_aprob >= target_exp:
                            failed_features.setdefault(target_layer_name, []).append(target_fid)
                            continue

                        if any(
                            target_aprob < source_exp and target_exp > source_aprob
                            for source_aprob, source_exp in source_ranges.values()
                        ):
                            failed_features.setdefault(target_layer_name, []).append(target_fid)

                if failed_features:
                    self.rulesWriter.validation_fail(rule=rule, verify=f"Verificati datele temporale sa corecte: {failed_features}")
                    return int(rule['tip_alerta_id']) != 1
                else:
                    self.rulesWriter.validation_pass(rule=rule)
                    return True

        except Exception:
            traceBack = traceback.format_exc()
            self.logger.error(
                f"[{self.__class__.__name__} - {self.zones_temporal_dates.__name__}] "
                f"Failed to verify if temporal dates from the zones don't overlap and are in chronological order.\n{traceBack}")
            self.rulesWriter.validation_error(rule=rule)
            return int(rule['tip_alerta_id']) != 1

    def _parse_zone_date(self, date_val) -> datetime | None:
        """Parse various date formats from GDAL for zone temporal checks."""
        if date_val is None:
            return None
        if isinstance(date_val, datetime):
            return date_val
        date_str = str(date_val).strip()
        if not date_str:
            return None
        for fmt in ("%Y-%m-%d", "%d-%m-%Y", "%Y/%m/%d", "%d/%m/%Y", "%Y.%m.%d", "%d.%m.%Y"):
            try:
                return datetime.strptime(date_str, fmt)
            except ValueError:
                continue
        return None
    
    # Rule Type 49 - RLU codes must exist in ZF/ZRS layers
    def regulament_zones_unique_codes(self,
            rule: dict[str, str],
            documentation_gpkg: gdal.Dataset,
            plan_type: Literal["PUG", "PUZ", "PUD", "PATJ", "PMUD"]) -> bool:
        """Verifies that every Cod_ZF_ZRS in RegulamentLocalUrbanism exists in ZFPropusa (Cod_ZF) or ZonaReglementareSuplimentara (Cod_ZRS)."""
        try:
            if plan_type in ["PUG", "PUZ", "PUD", "PATJ", "PMUD"]:
                failedFeatures: dict[str, list[int]] = {}
                ruleDataLayers: list[dict] = json.loads(rule["valoare_regula"])

                for ruleData in ruleDataLayers:
                    time.sleep(self.loopLimit)
                    validatedLayerName: str = ruleData["validated_layer"]
                    validatedField: str = ruleData["validated_field"]
                    validCodesFrom: list[dict] = ruleData["valid_codes_from"]

                    # Build the combined set of valid codes from all source layers
                    validCodes: set[str] = set()
                    for source in validCodesFrom:
                        time.sleep(self.loopLimit)
                        sourceLayer: ogr.Layer = documentation_gpkg.GetLayerByName(source["layer"])
                        if sourceLayer is None:
                            raise ValueError(f"Layer not found: {source['layer']}")
                        sourceLayer.ResetReading()
                        for sourceFeature in sourceLayer:
                            time.sleep(self.loopLimit)
                            fieldIdx = sourceFeature.GetFieldIndex(source["field"])
                            if fieldIdx < 0:
                                continue
                            val = sourceFeature.GetField(fieldIdx)
                            if val is not None:
                                validCodes.add(str(val))

                    # Check each RLU feature against the combined valid codes
                    validatedLayer: ogr.Layer = documentation_gpkg.GetLayerByName(validatedLayerName)
                    if validatedLayer is None:
                        raise ValueError(f"Layer not found: {validatedLayerName}")

                    validatedLayer.ResetReading()
                    for feature in validatedLayer:
                        time.sleep(self.loopLimit)
                        fid = feature.GetFID()
                        fieldIdx = feature.GetFieldIndex(validatedField)

                        if fieldIdx < 0:
                            failedFeatures.setdefault(validatedLayerName, []).append(fid)
                            continue

                        codeVal = feature.GetField(fieldIdx)
                        if codeVal is None:
                            failedFeatures.setdefault(validatedLayerName, []).append(fid)
                            continue

                        if str(codeVal) not in validCodes:
                            failedFeatures.setdefault(validatedLayerName, []).append(fid)

                if failedFeatures:
                    self.rulesWriter.validation_fail(rule=rule, verify=f"Coduri din RLU care nu se regasesc in ZF sau ZRS: {failedFeatures}")
                    return int(rule['tip_alerta_id']) != 1
                else:
                    self.rulesWriter.validation_pass(rule=rule)
                    return True

        except Exception:
            traceBack = traceback.format_exc()
            self.logger.error(
                f"[{self.__class__.__name__} - {self.regulament_zones_unique_codes.__name__}] "
                f"Failed to verify that RLU codes exist in ZF/ZRS layers.\n{traceBack}")
            self.rulesWriter.validation_error(rule=rule)
            return int(rule['tip_alerta_id']) != 1

    # Rule Type 52 - RLUD code+type pairs must exist in ZF/ZRS layers
    def regulament_detaliat_codes_types(self,
            rule: dict[str, str],
            documentation_gpkg: gdal.Dataset,
            plan_type: Literal["PUG", "PUZ", "PUD", "PATJ", "PMUD"]) -> bool:
        """Verifies that every (Cod_SZF_ZRS_D, Tip_SZF_ZRS_D) pair in RegulamentLocalUrbanismDetaliat exists in ZFPropusa (Cod_SZF, Tip_SZF) or ZonaReglementareSuplimentara (Cod_ZRS_D, Tip_ZRS_D)."""
        try:
            if plan_type in ["PUG", "PUZ", "PUD", "PATJ", "PMUD"]:
                failedFeatures: dict[str, list[int]] = {}
                ruleDataLayers: list[dict] = json.loads(rule["valoare_regula"])

                for ruleData in ruleDataLayers:
                    time.sleep(self.loopLimit)
                    validatedLayerName: str = ruleData["validated_layer"]
                    validatedFields: list[str] = ruleData["validated_fields"]
                    validPairsFrom: list[dict] = ruleData["valid_pairs_from"]

                    # Build combined set of valid (code, type) tuples from all source layers
                    validPairs: set[tuple[str, str]] = set()
                    for source in validPairsFrom:
                        time.sleep(self.loopLimit)
                        sourceLayer: ogr.Layer = documentation_gpkg.GetLayerByName(source["layer"])
                        if sourceLayer is None:
                            raise ValueError(f"Layer not found: {source['layer']}")
                        sourceLayer.ResetReading()
                        for sourceFeature in sourceLayer:
                            time.sleep(self.loopLimit)
                            codeIdx = sourceFeature.GetFieldIndex(source["fields"][0])
                            typeIdx = sourceFeature.GetFieldIndex(source["fields"][1])
                            if codeIdx < 0 or typeIdx < 0:
                                continue
                            codeVal = sourceFeature.GetField(codeIdx)
                            typeVal = sourceFeature.GetField(typeIdx)
                            if codeVal is not None and typeVal is not None:
                                validPairs.add((str(codeVal), str(typeVal)))

                    # Check each RLUD feature — both code and type must match a valid pair
                    validatedLayer: ogr.Layer = documentation_gpkg.GetLayerByName(validatedLayerName)
                    if validatedLayer is None:
                        raise ValueError(f"Layer not found: {validatedLayerName}")

                    validatedLayer.ResetReading()
                    for feature in validatedLayer:
                        time.sleep(self.loopLimit)
                        fid = feature.GetFID()
                        codeIdx = feature.GetFieldIndex(validatedFields[0])
                        typeIdx = feature.GetFieldIndex(validatedFields[1])

                        if codeIdx < 0 or typeIdx < 0:
                            failedFeatures.setdefault(validatedLayerName, []).append(fid)
                            continue

                        codeVal = feature.GetField(codeIdx)
                        typeVal = feature.GetField(typeIdx)

                        if codeVal is None or typeVal is None:
                            failedFeatures.setdefault(validatedLayerName, []).append(fid)
                            continue

                        if (str(codeVal), str(typeVal)) not in validPairs:
                            failedFeatures.setdefault(validatedLayerName, []).append(fid)

                if failedFeatures:
                    self.rulesWriter.validation_fail(rule=rule, verify=f"Combinatii Cod+Tip din RLUD care nu se regasesc in ZF sau ZRS: {failedFeatures}")
                    return int(rule['tip_alerta_id']) != 1
                else:
                    self.rulesWriter.validation_pass(rule=rule)
                    return True

        except Exception:
            traceBack = traceback.format_exc()
            self.logger.error(
                f"[{self.__class__.__name__} - {self.regulament_detaliat_codes_types.__name__}] "
                f"Failed to verify that RLUD code+type pairs exist in ZF/ZRS layers.\n{traceBack}")
            self.rulesWriter.validation_error(rule=rule)
            return int(rule['tip_alerta_id']) != 1

    # Rule Type 53 - Code-type consistency within each layer (same code must always have same type)
    def zones_code_type_consistency(self,
            rule: dict[str, str],
            documentation_gpkg: gdal.Dataset,
            plan_type: Literal["PUG", "PUZ", "PUD", "PATJ", "PMUD"]) -> bool:
        """Verifies that within each layer, a code value always maps to the same type. No same code with different types."""
        try:
            if plan_type in ["PUG", "PUZ", "PUD", "PATJ", "PMUD"]:
                failedFeatures: dict[str, list[int]] = {}
                ruleDataLayers: list[dict] = json.loads(rule["valoare_regula"])

                for ruleData in ruleDataLayers:
                    time.sleep(self.loopLimit)
                    layerName: str = ruleData["layer"]
                    codeField: str = ruleData["code_field"]
                    typeField: str = ruleData["type_field"]

                    layer: ogr.Layer = documentation_gpkg.GetLayerByName(layerName)
                    if layer is None:
                        raise ValueError(f"Layer not found: {layerName}")

                    # code -> (expected_type, first_fid)
                    codeTypeMap: dict[str, tuple[str, int]] = {}

                    layer.ResetReading()
                    for feature in layer:
                        time.sleep(self.loopLimit)
                        fid = feature.GetFID()
                        codeIdx = feature.GetFieldIndex(codeField)
                        typeIdx = feature.GetFieldIndex(typeField)

                        if codeIdx < 0 or typeIdx < 0:
                            failedFeatures.setdefault(layerName, []).append(fid)
                            continue

                        codeVal = feature.GetField(codeIdx)
                        typeVal = feature.GetField(typeIdx)

                        if codeVal is None or typeVal is None:
                            failedFeatures.setdefault(layerName, []).append(fid)
                            continue

                        codeStr = str(codeVal)
                        typeStr = str(typeVal)

                        if codeStr not in codeTypeMap:
                            codeTypeMap[codeStr] = (typeStr, fid)
                        elif codeTypeMap[codeStr][0] != typeStr:
                            # Conflict: same code, different type — mark current feature
                            failedFeatures.setdefault(layerName, []).append(fid)
                            # Also mark the first occurrence (once)
                            firstFid = codeTypeMap[codeStr][1]
                            if firstFid != -1:
                                failedFeatures.setdefault(layerName, []).append(firstFid)
                                codeTypeMap[codeStr] = (codeTypeMap[codeStr][0], -1)

                if failedFeatures:
                    self.rulesWriter.validation_fail(rule=rule, verify=f"Coduri cu tipologii inconsistente: {failedFeatures}")
                    return int(rule['tip_alerta_id']) != 1
                else:
                    self.rulesWriter.validation_pass(rule=rule)
                    return True

        except Exception:
            traceBack = traceback.format_exc()
            self.logger.error(
                f"[{self.__class__.__name__} - {self.zones_code_type_consistency.__name__}] "
                f"Failed to verify code-type consistency within layers.\n{traceBack}")
            self.rulesWriter.validation_error(rule=rule)
            return int(rule['tip_alerta_id']) != 1

    # Rule Type 55 - LimitaIntravilan layers must contain only SIRUTA/Judet/UAT combinations present in PlanSpatial
    def intravilan_spatial_combinations(self,
            rule: dict[str, str],
            documentation_gpkg: gdal.Dataset,
            plan_type: Literal["PUG", "PUZ", "PUD", "PATJ", "PMUD"]) -> bool:
        """Verifies that every (SIRUTA, Judet, UAT) combination in LimitaIntravilanPropusa and LimitaIntravilanExistenta exists in PlanSpatial."""
        try:
            if plan_type in ["PUG", "PUZ", "PUD", "PATJ", "PMUD"]:
                failedFeatures: dict[str, list[int]] = {}
                ruleData: dict = json.loads(rule["valoare_regula"])

                sourceLayerName: str = ruleData["source_layer"]
                sourceFields: list[str] = ruleData["source_fields"]
                validatedLayers: list[dict] = ruleData["validated_layers"]

                # Build the set of valid combinations from PlanSpatial
                sourceLayer: ogr.Layer = documentation_gpkg.GetLayerByName(sourceLayerName)
                if sourceLayer is None:
                    raise ValueError(f"Layer not found: {sourceLayerName}")

                validCombinations: set[tuple] = set()
                sourceLayer.ResetReading()
                for feature in sourceLayer:
                    time.sleep(self.loopLimit)
                    values: list[str] = []
                    valid: bool = True
                    for field in sourceFields:
                        fieldIdx = feature.GetFieldIndex(field)
                        if fieldIdx < 0:
                            valid = False
                            break
                        val = feature.GetField(fieldIdx)
                        if val is None:
                            valid = False
                            break
                        values.append(str(val))
                    if valid:
                        validCombinations.add(tuple(values))

                # Check each validated layer against the PlanSpatial combinations
                for layerDef in validatedLayers:
                    time.sleep(self.loopLimit)
                    layerName: str = layerDef["layer"]
                    layerFields: list[str] = layerDef["fields"]

                    layer: ogr.Layer = documentation_gpkg.GetLayerByName(layerName)
                    if layer is None:
                        raise ValueError(f"Layer not found: {layerName}")

                    layer.ResetReading()
                    for feature in layer:
                        time.sleep(self.loopLimit)
                        fid = feature.GetFID()
                        values: list[str] = []
                        valid: bool = True
                        for field in layerFields:
                            fieldIdx = feature.GetFieldIndex(field)
                            if fieldIdx < 0:
                                valid = False
                                break
                            val = feature.GetField(fieldIdx)
                            if val is None:
                                valid = False
                                break
                            values.append(str(val))

                        if not valid:
                            failedFeatures.setdefault(layerName, []).append(fid)
                            continue

                        if tuple(values) not in validCombinations:
                            failedFeatures.setdefault(layerName, []).append(fid)

                if failedFeatures:
                    self.rulesWriter.validation_fail(rule=rule, verify=f"Combinatii SIRUTA/Judet/UAT care nu se regasesc in PlanSpatial: {failedFeatures}")
                    return int(rule['tip_alerta_id']) != 1
                else:
                    self.rulesWriter.validation_pass(rule=rule)
                    return True

        except Exception:
            traceBack = traceback.format_exc()
            self.logger.error(
                f"[{self.__class__.__name__} - {self.intravilan_spatial_combinations.__name__}] "
                f"Failed to verify SIRUTA/Judet/UAT combinations against PlanSpatial.\n{traceBack}")
            self.rulesWriter.validation_error(rule=rule)
            return int(rule['tip_alerta_id']) != 1
