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

"""
/***************************************************************************
 GeoCAR
                                 A QGIS plugin
 Cadastro Ambiental Rural
 Generated by Plugin Builder: http://g-sherman.github.io/Qgis-Plugin-Builder/
                              -------------------
        begin                : 2026-02-10
        copyright            : (C) 2026 by Prof Cazaroli 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__ = 'Prof Cazaroli e Leandro França'
__date__ = '2026-02-10'
__copyright__ = '(C) 2026 by Prof Cazaroli e Leandro França'

__revision__ = '$Format:%H$'

from qgis.PyQt.QtCore import QCoreApplication
from qgis.PyQt.QtGui import QIcon
import os
from geocar.images.Imgs import *
import processing
from qgis.core import (
    QgsProject,
    QgsMapLayer,
    QgsWkbTypes,
    QgsFeature,
    QgsCoordinateTransform,
    QgsProcessing,
    QgsProcessingAlgorithm,
    QgsProcessingParameterVectorLayer,
    QgsProcessingParameterNumber,
    QgsProcessingParameterEnum,
    QgsProcessingException,
    QgsProcessingUtils,
    QgsCoordinateReferenceSystem
)

class linha_aux_Poligono(QgsProcessingAlgorithm):
    INPUT_LINE = 'INPUT_LINE'
    BUFFER_WIDTH = 'BUFFER_WIDTH'
    INPUT_ATI = 'INPUT_ATI'
    OUTPUT_LIN = 'OUTPUT_LIN'

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

    def createInstance(self):
        return linha_aux_Poligono()

    def name(self):
        return 'linha_aux_Poligono'

    def displayName(self):
        return self.tr('3. Linha Auxiliar para Polígono')

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

    def groupId(self):
        return ''

    def icon(self):
        return QIcon(os.path.join(os.path.dirname(os.path.dirname(__file__)), 'images/geocar.png'))

    def shortHelpString(self):
        txt = """Converte uma camada de <b>Linha_Auxiliar</b> em um polígono com largura definida pelo usuário, útil para representar elementos lineares que possuem largura real no terreno, como <b>rios, estradas ou canais</b>.
O algoritmo gera um buffer a partir da linha, reprojeta automaticamente para UTM para garantir a largura em metros, intersecta com a camada <b>ATI</b> e adiciona o polígono resultante diretamente na camada de destino (<b>RIO ou SA</b>).
<b>Parâmetros principais:</b>
• Linha_Auxiliar – camada de linhas de entrada  
• Largura total (m) – largura do elemento no terreno 
• ATI – Área Total do Imóvel
• Camada destino – camada poligonal que receberá as feições
"""

        footer = '''<div>
                      <div align="center">
                      <img style="width: 100%; height: auto;" src="data:image/jpg;base64,'''+ CAR_GeoOne +'''
                      </div>
                      <div align="right">
                      <p align="right">
                      <a href="https://geoone.com.br/pvcar/"><span style="font-weight: bold;">Conheça o curso de Cadastro Ambiental Rural (CAR)</span></a>
                      </p>
                      <p align="right">
                      <a href="https://portal.geoone.com.br/m/lessons/car?classId=6085"><span style="font-weight: bold;">Acesse a aula sobre esta ferramenta no curso de CAR da GeoOne</span></a>
                      </p>
                      <a target="_blank" rel="noopener noreferrer" href="https://geoone.com.br/"><img 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 initAlgorithm(self, config=None):
        self.addParameter(QgsProcessingParameterVectorLayer(self.INPUT_LINE, self.tr('Selecione a Linha_Auxiliar (4674)'), [QgsProcessing.TypeVectorLine], defaultValue='Linha_Auxiliar'))
        self.addParameter(QgsProcessingParameterNumber(self.BUFFER_WIDTH, self.tr('Largura total (metros)'), type=QgsProcessingParameterNumber.Double, defaultValue=10.0))
        self.addParameter(QgsProcessingParameterVectorLayer(self.INPUT_ATI, self.tr('Selecione a camada ATI'), [QgsProcessing.TypeVectorPolygon], defaultValue='ATI'))

        camadas_projeto = QgsProject.instance().mapLayers().values()
        self.camadas_saida = [
            lyr for lyr in camadas_projeto
            if lyr.type() == QgsMapLayer.VectorLayer
            and lyr.geometryType() == QgsWkbTypes.PolygonGeometry
            and (lyr.name().upper().startswith("RIO") or lyr.name().upper().startswith("SA"))
        ]

        nomes_saida = [lyr.name() for lyr in self.camadas_saida]
        if not nomes_saida:
            nomes_saida = [self.tr('Nenhuma camada RIO/SA encontrada')]

        self.addParameter(QgsProcessingParameterEnum(self.OUTPUT_LIN, self.tr('Escolha a camada destino (RIO/SA)'), options=nomes_saida))

    def processAlgorithm(self, parameters, context, feedback):
        line_lyr = self.parameterAsVectorLayer(parameters, self.INPUT_LINE, context)
        ati_lyr = self.parameterAsVectorLayer(parameters, self.INPUT_ATI, context)
        width = self.parameterAsDouble(parameters, self.BUFFER_WIDTH, context)
        
        idx = self.parameterAsEnum(parameters, self.OUTPUT_LIN, context)
        if not self.camadas_saida:
            raise QgsProcessingException("Nenhuma camada de destino selecionada.")
        dest_layer = self.camadas_saida[idx]

        if feedback.isCanceled(): return {}

        # --- PASSO 1: DETECTAR FUSO UTM PARA BUFFER PRECISO ---
        extent = line_lyr.extent()
        center_x = (extent.xMinimum() + extent.xMaximum()) / 2
        center_y = (extent.yMinimum() + extent.yMaximum()) / 2
        utm_zone = int((center_x + 180) / 6) + 1
        epsg_utm = 32700 + utm_zone if center_y < 0 else 32600 + utm_zone
        target_crs = f"EPSG:{epsg_utm}"
        
        feedback.pushInfo(f"Fuso detectado: {target_crs}. Reprojetando para Buffer...")

        # --- PASSO 2: REPROJETAR -> DISSOLVE -> BUFFER (Em Metros) ---
        reprojected = processing.run("native:reprojectlayer", {
            'INPUT': line_lyr, 'TARGET_CRS': target_crs, 'OUTPUT': 'memory:'
        }, context=context, feedback=feedback, is_child_algorithm=True)['OUTPUT']

        dissolved = processing.run("native:dissolve", {
            'INPUT': reprojected, 'OUTPUT': 'memory:'
        }, context=context, feedback=feedback, is_child_algorithm=True)['OUTPUT']

        buffered = processing.run("native:buffer", {
            'INPUT': dissolved,
            'DISTANCE': width / 2,
            'END_CAP_STYLE': 1, # Flat
            'DISSOLVE': True,
            'OUTPUT': 'memory:'
        }, context=context, feedback=feedback, is_child_algorithm=True)['OUTPUT']

        # --- PASSO 3: VOLTAR PARA 4674 E INTERSECCIONAR ---
        buffer_4674 = processing.run("native:reprojectlayer", {
            'INPUT': buffered, 'TARGET_CRS': 'EPSG:4674', 'OUTPUT': 'memory:'
        }, context=context, feedback=feedback, is_child_algorithm=True)['OUTPUT']

        intersected = processing.run("native:intersection", {
            'INPUT': buffer_4674, 'OVERLAY': ati_lyr, 'OUTPUT': 'memory:'
        }, context=context, feedback=feedback, is_child_algorithm=True)['OUTPUT']

        # --- PASSO 4: LIMPEZA FINAL ---
        try:
            cleaned = processing.run("native:fixgeometries", {'INPUT': intersected, 'OUTPUT': 'memory:'}, context=context, feedback=feedback, is_child_algorithm=True)['OUTPUT']
        except:
            cleaned = intersected

        final_vlayer = QgsProcessingUtils.mapLayerFromString(cleaned, context)

        # --- PASSO 5: INJETAR NA CAMADA DE DESTINO ---
        if not dest_layer.isEditable():
            dest_layer.startEditing()
        
        # Transformação de coordenadas
        xform = QgsCoordinateTransform(final_vlayer.crs(), dest_layer.crs(), QgsProject.instance())
        
        novas_feicoes = []
        for feat in final_vlayer.getFeatures():
            # Criamos a feição com os campos da camada de destino para evitar erro de esquema
            new_feat = QgsFeature(dest_layer.fields()) 
            geom = feat.geometry()
            geom.transform(xform)
            new_feat.setGeometry(geom)
            novas_feicoes.append(new_feat)

        # Adiciona as feições
        if novas_feicoes:
            dest_layer.addFeatures(novas_feicoes)
            success = dest_layer.commitChanges()
            
            if not success:
                feedback.reportError(f"Erro ao salvar: {dest_layer.commitErrors()}")
        
        # --- ATUALIZAÇÃO SEGURA (SEM MAPCANVAS) ---
        dest_layer.updateExtents()
        
        # O triggerRepaint avisa ao QGIS para redesenhar a camada onde quer que ela esteja
        dest_layer.triggerRepaint() 
        
        feedback.pushInfo(f"Sucesso! {len(novas_feicoes)} feição(ões) adicionada(s) em {dest_layer.name()}.")
        
        return {self.OUTPUT_LIN: dest_layer.id()}