from __future__ import annotations

import warnings
from typing import Any

from qgis.core import (
    QgsProcessingContext,
    QgsProcessingFeedback,
    QgsProcessingParameterBoolean,
    QgsProcessingParameterCrs,
    QgsProcessingParameterDefinition,
    QgsProcessingParameterFeatureSink,
)
from qgis.PyQt.QtGui import QIcon

from gusnet.elements import FieldGroup, ModelLayer
from gusnet.feature_writer import get_qgs_fields
from gusnet.gusnet_processing.common import CommonProcessingBase
from gusnet.i18n import tr
from gusnet.profiler import profile


class TemplateLayers(CommonProcessingBase):
    CRS = "CRS"

    def createInstance(self):  # noqa N802
        return TemplateLayers()

    def name(self) -> str:
        return "template_layers"

    def displayName(self) -> str:  # noqa N802
        return tr("Create Template Layers")

    def shortHelpString(self) -> str:  # noqa N802
        return tr("""
        This will create a set of 'template' layers, which you can use for building your model.
        You do not need to create or use all layers if not required for your model.
        """)

    def icon(self):
        return QIcon(":images/themes/default/mActionFileNew.svg")

    def initAlgorithm(self, config=None):  # noqa N802
        self.addParameter(QgsProcessingParameterCrs(self.CRS, tr("Coordinate Reference System (CRS)"), "ProjectCrs"))

        advanced_analysis_types = [
            (FieldGroup.WATER_QUALITY_ANALYSIS, tr("Create Fields for Water Quality Analysis")),
            (FieldGroup.ENERGY, tr("Create Fields for Energy Analysis")),
        ]
        for analysis_type, description in advanced_analysis_types:
            param = QgsProcessingParameterBoolean(
                analysis_type.name, tr(description), optional=True, defaultValue=False
            )
            param.setFlags(param.flags() | QgsProcessingParameterDefinition.FlagAdvanced)
            self.addParameter(param)

        for layer in ModelLayer:
            self.addParameter(QgsProcessingParameterFeatureSink(layer.name, layer.friendly_name))

    @profile(tr("Create Template Layers"))
    def processAlgorithm(  # noqa N802
        self,
        parameters: dict[str, Any],
        context: QgsProcessingContext,
        feedback: QgsProcessingFeedback | None,  # noqa: ARG002
    ) -> dict:
        analysis_types_to_use = FieldGroup.BASE
        for analysis_type in FieldGroup:
            if self.parameterAsBoolean(parameters, str(analysis_type.name), context):
                analysis_types_to_use = analysis_types_to_use | analysis_type

        crs = self.parameterAsCrs(parameters, self.CRS, context)

        # for shapefile writing
        warnings.filterwarnings("ignore", "Field", RuntimeWarning)
        warnings.filterwarnings("ignore", "Normalized/laundered field name:", RuntimeWarning)

        outputs: dict[str, str] = {}
        for layer in ModelLayer:
            field_enums = [field for field in layer.wq_fields() if field.field_group & analysis_types_to_use]
            fields = get_qgs_fields(field_enums)
            (_, outputs[layer]) = self.parameterAsSink(parameters, layer, context, fields, layer.wkb_type, crs)

        self._setup_postprocessing(context, outputs, tr("Model Layers"), True)

        return outputs
