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

"""
/***************************************************************************
 GeoINCRA
                                 A QGIS plugin
 Georreferenciamento de Imóveis Rurais
 Generated by Plugin Builder: http://g-sherman.github.io/Qgis-Plugin-Builder/
                              -------------------
        begin                : 2022-02-13
        copyright            : (C) 2022 by Tiago Prudencio e Leandro França
        email                : contato@geoone.com.br
 ***************************************************************************/

/***************************************************************************
 *                                                                         *
 *   This program is free software; you can redistribute it and/or modify  *
 *   it under the terms of the GNU General Public License as published by  *
 *   the Free Software Foundation; either version 2 of the License, or     *
 *   (at your option) any later version.                                   *
 *                                                                         *
 ***************************************************************************/
"""

__author__ = 'Tiago Prudencio e Leandro França'
__date__ = '2024-08-11'
__copyright__ = '(C) 2024 by Tiago Prudencio e Leandro França'

# This will get replaced with a git SHA1 when you do a git archive

__revision__ = '$Format:%H$'

from qgis.PyQt.QtCore import QCoreApplication, QVariant
from qgis.core import *
import os
import requests
from qgis.PyQt.QtGui import QIcon, QFont, QColor
from GeoINCRA.images.Imgs import *


class LayersOfInterest(QgsProcessingAlgorithm):

    OUTPUT = 'OUTPUT'
    EXTENT = 'EXTENT'
    WFS = 'WFS'

    mapping ={
               0: 'Áreas de Conservação 2025 (ICMBio)',
               1: 'Áreas Embargadas (ICMBio)',
               2: 'Áreas Urbanizadas 2019 (IBGE)',
               3: 'Terras Indígenas 2017 (IBGE)',
               4: 'Unidades da Federação 2025 (IBGE)',
               5: 'Municípios 2025 (IBGE)',
               6: 'Estações BDG GPS (IBGE)',
               7: 'Faixa de domínio 2021 (DNIT)',
               8: 'RBMC 2024 (IBGE)',
            }


    links = {
                  mapping[0]: "pagingEnabled='true' preferCoordinatesForWfsT11='false' restrictToRequestBBOX='1' srsname='EPSG:4674' typename='ICMBio:limiteucsfederais_a' url='https://geoservicos.inde.gov.br/geoserver/ICMBio/ows?layers=limiteucsfederais_a&styles=&bbox=-73.99121093750001,-32.92391970862839,-25.290946960449205,5.271910667501984&width=329&height=245&tiled=true&srs=EPSG:4326&transparent=true' url='https://geoservicos.inde.gov.br/geoserver/ICMBio/ows?version=1.1.0&layers=limiteucsfederais_a&styles=&bbox=-73.99121093750001,-32.92391970862839,-25.290946960449205,5.271910667501984&width=329&height=245&tiled=true&srs=EPSG:4326&transparent=true' version='auto'",
                  mapping[1]: "pagingEnabled='true' preferCoordinatesForWfsT11='false' restrictToRequestBBOX='1' srsname='EPSG:4674' typename='ICMBio:embargos_icmbio' url='https://geoservicos.inde.gov.br/geoserver/ICMBio/ows' url='https://geoservicos.inde.gov.br/geoserver/ICMBio/ows?version=2.0.0' version='auto'",
                  mapping[2]: "pagingEnabled='true' preferCoordinatesForWfsT11='false' restrictToRequestBBOX='1' srsname='EPSG:4674' typename='CGEO:AU_2022_AreasUrbanizadas2019_Brasil' url='https://geoservicos.ibge.gov.br/geoserverCGEO/ows' http-header:referer=''",
                  mapping[3]: "pagingEnabled='true' preferCoordinatesForWfsT11='false' restrictToRequestBBOX='1' srsname='EPSG:4674' typename='CGEO:andb2022_ct30103' url='https://geoservicos.ibge.gov.br/geoserverCGEO/ows' version='auto'",
                  mapping[4]: "pagingEnabled='true' preferCoordinatesForWfsT11='false' restrictToRequestBBOX='1' srsname='EPSG:4674' typename='CCAR:BC250_2025_lml_unidade_federacao_a' url='https://geoservicos.ibge.gov.br/geoserverCCAR/ows' version='auto'", # antigo: CCAR:BC250_2023_Unidade_Federacao_A
                  mapping[5]: "pagingEnabled='true' preferCoordinatesForWfsT11='false' restrictToRequestBBOX='1' srsname='EPSG:4674' typename='CCAR:BC250_2025_lml_municipio_a' url='https://geoservicos.ibge.gov.br/geoserverCCAR/ows' version='auto'", # antigo: CCAR:BC250_2023_Municipio_A
                  mapping[6]: "pagingEnabled='true' preferCoordinatesForWfsT11='false' restrictToRequestBBOX='1' srsname='EPSG:4674' typename='GeoINCRA:Estacoes_BDG_GPS_2024' url='http://geoonecloud.com/geoserver/ows' version='auto'", # antigo: CGEO:ANMS2010_09_estacoes_GPS_2010
                  mapping[7]: "pagingEnabled='true' preferCoordinatesForWfsT11='false' restrictToRequestBBOX='1' srsname='EPSG:4674' typename='GeoINCRA:faixa_dominio_dnit_2024' url='http://geoonecloud.com/geoserver/ows' version='auto'",
                  mapping[8]: "pagingEnabled='true' preferCoordinatesForWfsT11='false' restrictToRequestBBOX='1' srsname='EPSG:4674' typename='GeoINCRA:RBMC_2024' url='http://geoonecloud.com/geoserver/ows' version='auto'",
            }

    def initAlgorithm(self, config):

        self.addParameter(
            QgsProcessingParameterExtent(
                self.EXTENT,
                self.tr('Retângulo de Extensão')
            )
        )

        my_settings = QgsSettings()
        my_user_layer = my_settings.value("GeoINCRA/geoincra_user_layer", 0)

        self.addParameter(
            QgsProcessingParameterEnum(
                self.WFS,
                self.tr('Camada de interesse'),
                options = self.links.keys(),
                defaultValue= my_user_layer
            )
        )

        self.addParameter(
            QgsProcessingParameterFeatureSink(
                self.OUTPUT,
                self.tr('Camada exportada')
            )
        )

    def processAlgorithm(self, parameters, context, feedback):

        extensao = self.parameterAsExtent(
        parameters,
        self.EXTENT,
        context
        )
        if not extensao:
            raise QgsProcessingException(self.invalidSourceError(parameters, self.EXTENT))


        option = self.parameterAsEnum(parameters, self.WFS, context)
        self.OPTION = option
        layer = self.mapping[option]
        link = self.links[layer]
        my_settings = QgsSettings()
        my_settings.setValue("GeoINCRA/geoincra_user_layer", option)

        source = QgsVectorLayer(link, "my wfs layer", "WFS")
        (sink, dest_id) = self.parameterAsSink(
            parameters,
            self.OUTPUT,
            context,
            source.fields(),
            source.wkbType(),
            source.sourceCrs()
        )

        if sink is None:
            raise QgsProcessingException(self.invalidSinkError(parameters, self.OUTPUT))

        crsSrc = QgsCoordinateReferenceSystem(QgsProject().instance().crs())
        crsDest = source.sourceCrs()
        proj2geo = QgsCoordinateTransform(crsSrc, crsDest, QgsProject.instance())
        extensao = proj2geo.transform(extensao)

        request = QgsFeatureRequest().setFilterRect(extensao)

        if option != -1: # quando o request não funcionar
            for feature in source.getFeatures(request):
                if feedback.isCanceled():
                    break
                sink.addFeature(feature, QgsFeatureSink.FastInsert)
        else:
            tam = source.featureCount()
            Percent = 100/tam if tam>0 else 0
            for current, feature in enumerate(source.getFeatures()):
                geom = feature.geometry()
                if geom.intersects(extensao):
                    sink.addFeature(feature, QgsFeatureSink.FastInsert)
                if feedback.isCanceled():
                    break
                feedback.setProgress(int((current+1) * Percent))

        global renamer
        renamer = Renamer(layer)
        context.layerToLoadOnCompletionDetails(dest_id).setPostProcessor(renamer)
        self.SAIDA = dest_id
        return {self.OUTPUT: dest_id}


    def name(self):
        return 'LayersOfInterest'.lower()

    def displayName(self):
        return self.tr('Camadas de Interesse')

    def group(self):
        return self.tr(self.groupId())

    def groupId(self):
        return ''

    def tr(self, string):
        return QCoreApplication.translate('Processing', string)

    def createInstance(self):
        return LayersOfInterest()

    def icon(self):
        return QIcon(os.path.join(os.path.dirname(os.path.dirname(__file__)), 'images/geoincra_pb.png'))
    
    def tags(self):
        return 'GeoOne,GeoRural,INCRA,Sigef,IBGE,DNIT,municípios,estados,brasil,faixa de domínio,RBMC,ICMBio,conservação,embargadas,gps,urbanizadas,rural,regularização,fundiária'.split(',')

    def shortHelpString(self):
        txt = 'Baixar camada de interesse a partir de uma extensão (retângulo).'
        footer = '''<div>
                      <div align="center">
                      <img style="width: 100%; height: auto;" src="data:image/jpg;base64,'''+ INCRA_GeoOne +'''
                      </div>
                      <div align="right">
                      <p align="right">
                      <a href="https://geoone.com.br/pvgeoincra2/"><span style="font-weight: bold;">Conheça o curso de GeoINCRA no QGIS</span></a>
                      </p>
                      <p align="right">
                      <a href="https://portal.geoone.com.br/m/lessons/georreferenciamento-de-imveis-rurais-com-o-plugin-geoincra-1690158094835"><span style="font-weight: bold;">Acesse seu curso na GeoOne</span></a>
                      </p>
                      <a target="_blank" rel="noopener noreferrer" href="https://geoone.com.br/"><img height="80" title="GeoOne" src="data:image/png;base64,'''+ GeoOne +'''"></a>
                      <p><i>"Mapeamento automatizado, fácil e direto ao ponto é na GeoOne!"</i></p>
                      </div>
                    </div>'''
        return txt + footer
    def postProcessAlgorithm(self, context, feedback):
        layer = QgsProcessingUtils.mapLayerFromString(self.SAIDA, context)
        nome = 'nome'
        if layer.featureCount() > 0:
            if self.OPTION == 8: # RBMC
                # Simbologia
                rbmc_dict = {}
                # URL que você deseja acessar
                url = "http://170.84.40.52:2101/"
                # Enviar uma requisição GET para o servidor
                try:
                    response = requests.get(url)
                    if response.status_code == 200:
                        page_text = response.text
                        linhas = page_text.split('\n')
                        for linha in linhas:
                            att = linha.split(';')
                            if len(att) > 13 and att[0] == 'STR' and len(att[1]) == 5:
                                code = att[1]
                                format_rtc = att[3]
                                gnss = att[6]
                                status = att[5]
                                software = att[13]
                                rbmc_dict[code] = {
                                    "format_rtc": format_rtc,
                                    "gnss": gnss,
                                    "status": status,
                                    "software": software,
                            }

                    # Criar lista de estações ON
                    ON = []
                    OFF = []
                    for feat in layer.getFeatures():
                        codigo = feat['nome']
                        if (codigo + '0' in rbmc_dict) or (codigo + '1' in rbmc_dict):
                            ON.append(codigo)
                        else:
                            OFF.append(codigo)

                    # Criar a simbologia baseada em regras
                    root_rule = QgsRuleBasedRenderer.Rule(None)

                    # RBMC inoperante
                    regra1 = QgsRuleBasedRenderer.Rule(QgsSymbol.defaultSymbol(layer.geometryType()))
                    filtro1 = '"nome" in ' + str(tuple(OFF)).replace(',)', ')') if len(OFF) > 0 else 'ELSE'
                    regra1.setFilterExpression(filtro1)  # Expressão de filtragem
                    regra1.setLabel("Inoperante")  # Rótulo da regra
                    regra1.symbol().setColor(QColor("#FF0000"))  # Cor vermelha
                    regra1.symbol().setSize(2.5)  # Tamanho do símbolo
                    root_rule.appendChild(regra1)

                    # RBMC operante
                    regra2 = QgsRuleBasedRenderer.Rule(QgsSymbol.defaultSymbol(layer.geometryType()))
                    filtro2 = '"nome" in ' + str(tuple(ON)).replace(',)', ')') if len(ON) > 0 else 'ELSE'
                    regra2.setFilterExpression(filtro2) 
                    regra2.setLabel("Operante")
                    regra2.symbol().setColor(QColor("#00FF00"))  # Cor verde
                    regra2.symbol().setSize(2.5)  # Tamanho do símbolo
                    root_rule.appendChild(regra2)

                    # Aplicar a simbologia baseada em regras na camada
                    renderer = QgsRuleBasedRenderer(root_rule)
                    layer.setRenderer(renderer)
                
                    acManager = layer.actions()
                    acActor = QgsAction(QgsAction.ActionType.GenericPython , self.tr('Abrir descritivo'),"""
import webbrowser
webbrowser.open("[%URL_LINK%]")""", False)
                    acActor.setActionScopes({'Field', 'Layer', 'Canvas', 'Feature'})
                    acManager.addAction(acActor)

                except:
                    print('Erro no processo requisição da URL!')
            
            elif self.OPTION == 6: # Estação GPS
                nome = 'ESTACAO'
                # Cria o símbolo de triângulo vermelho
                symbol = QgsMarkerSymbol.createSimple({
                    'name': 'triangle',      # forma do marcador
                    'color': '255,0,0',      # vermelho (R,G,B)
                    'outline_color': '0,0,0',# borda preta (opcional)
                    'outline_style': 'solid',
                    'size': '3',             # tamanho em mm
                    'size_unit': 'MM',
                    'angle': '0'             # 0 = triângulo “apontando para cima”
                })

                # Cria um renderer de símbolo único e aplica na camada
                renderer = QgsSingleSymbolRenderer(symbol)
                layer.setRenderer(renderer)
                layer.triggerRepaint()
                
                acManager = layer.actions()
                acActor = QgsAction(QgsAction.ActionType.GenericPython , self.tr('Abrir relatório'),"""
import webbrowser
url = "http://www.bdg.ibge.gov.br/bdg/pdf/relatorio.asp?L1=" + str([%ESTACAO%])
webbrowser.open(url)""", False)
                acActor.setActionScopes({'Field', 'Layer', 'Canvas', 'Feature'})
                acManager.addAction(acActor)

            # Rotulação
            # Configurar as propriedades de rótulo
            label_settings = QgsPalLayerSettings()
            label_settings.fieldName = f'"{nome}"'
            label_settings.isExpression = True
            # label_settings.placement = QgsPalLayerSettings.AroundPoint
            label_settings.enabled = True

            # Configurar o estilo do texto
            text_format = QgsTextFormat()
            font = QFont("Arial", 10)
            font.setBold(True)
            text_format.setFont(font)
            text_format.setSize(10)
            text_format.setColor(QColor("white"))

            # Configurar o buffer
            buffer_settings = QgsTextBufferSettings()
            buffer_settings.setEnabled(True)
            buffer_settings.setSize(0.5)
            buffer_settings.setColor(QColor("black"))
            text_format.setBuffer(buffer_settings)

            # Aplicar o estilo de texto no rótulo
            label_settings.setFormat(text_format)

            # Configurar e ativar os rótulos
            labeling = QgsVectorLayerSimpleLabeling(label_settings)
            layer.setLabeling(labeling)
            layer.setLabelsEnabled(True)
            layer.triggerRepaint()

        return {}

class Renamer (QgsProcessingLayerPostProcessorInterface):
    def __init__(self, layer_name):
        self.name = layer_name
        super().__init__()

    def postProcessLayer(self, layer, context, feedback):
        layer.setName(self.name)
