# -*- coding: utf-8 -*-
"""
/***************************************************************************
 Sewercalc
                                 A QGIS plugin
 Plugin para dimensionamento de redes coletoras de esgoto 
 Generated by Plugin Builder: http://g-sherman.github.io/Qgis-Plugin-Builder/
                              -------------------
        begin                : 2025-02-07
        git sha              : $Format:%H$
        copyright            : (C) 2025 by Wanderilo  Lima
        email                : Wanderilo Lima
 ***************************************************************************/

/***************************************************************************
 *                                                                         *
 *   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.                                   *
 *                                                                         *
 ***************************************************************************/
"""


from qgis.core import QgsProject, QgsPointXY, QgsProcessingException, Qgis, QgsVectorLayer, QgsPoint, QgsRectangle
from PyQt5.QtCore import QVariant
from qgis.utils import iface
from qgis.PyQt.QtWidgets import QMessageBox

from .Sewercalc_Add_colunas_funcao import Add_colunas
from .Sewercalc_Informacoes import verificar_camadas
from .Sewercalc_Preencher_campos import calcular_comprimento_rede
from .Sewercalc_config_cx_txt import carregar_configuracoes
from .Sewercalc_Estilo import aplicar_estilo
import json

layer_pv = ""
layer_rede = ""
bifurcacoes = []

#---------------------------------------------------------------------------------------------
def adicionar_colunas():
    global layer_rede, layer_pv
    Add_colunas(layer_pv, [
        ("NUM", QVariant.Int, 10),
        ("NOME", QVariant.String, 50)
    ])
    Add_colunas(layer_rede, [
        ("COLETOR", QVariant.Int, 10),
        ("TRECHO", QVariant.Int, 10),
        ("NOME", QVariant.String, 50)
    ])
#---------------------------------------------------------------------------------------------
def obter_ponto_inicial(geometry):
    if geometry.isMultipart():
        linhas = geometry.asMultiPolyline()
        if linhas:
            return QgsPointXY(linhas[0][0])
    else:
        linha = geometry.asPolyline()
        if linha:
            return QgsPointXY(linha[0])
    return None

def obter_ponto_final(geometry):
    if geometry.isMultipart():
        linhas = geometry.asMultiPolyline()
        if linhas:
            return QgsPointXY(linhas[-1][-1])
    else:
        linha = geometry.asPolyline()
        if linha:
            return QgsPointXY(linha[-1])
    return None

def obter_pv_no_ponto(camada_pv, ponto):
    """Retorna o PV que está na posição do ponto especificado."""
    for pv in camada_pv.getFeatures():
        if pv.geometry().asPoint().distance(ponto) < 0.05:  # Pequena margem de tolerância
            return pv
    return None
#---------------------------------------------------------------------------------------------
def encontrar_proximo_trecho(camada_rede, id_trecho_atual):
    
    trecho_atual = camada_rede.getFeature(id_trecho_atual)
    if not trecho_atual.isValid():
        print(f"ERRO: Trecho com ID {id_trecho_atual} não encontrado")
        return None
    
    geom = trecho_atual.geometry()
    if geom.isMultipart():
        vertices = geom.asMultiPolyline()[0]
    else:
        vertices = geom.asPolyline()
    
    if len(vertices) < 2:
        print(f"ERRO: Trecho {id_trecho_atual} tem menos de 2 vértices")
        return None
    
    ponto_final = QgsPoint(vertices[-1])
    ponto_final_chave = (ponto_final.x(), ponto_final.y())

    trechos_conectados = []
    
    for feature in camada_rede.getFeatures():
        if feature.id() == id_trecho_atual:
            continue 
        
        feat_geom = feature.geometry()
        if feat_geom.isMultipart():
            feat_vertices = feat_geom.asMultiPolyline()[0]
        else:
            feat_vertices = feat_geom.asPolyline()
        
        if len(feat_vertices) < 2:
            continue
        
        ponto_inicial = QgsPoint(feat_vertices[0])
        ponto_inicial_chave = (ponto_inicial.x(), ponto_inicial.y())
        
        if ponto_inicial_chave == ponto_final_chave:
            trechos_conectados.append(feature.id())
    
    if len(trechos_conectados) == 0:
        return None
    elif len(trechos_conectados) == 1:
        return trechos_conectados[0]
    else:
        # Armazena a bifurcação para depois mostrar tudo junto
        existe = any(b['id_trecho_atual'] == id_trecho_atual for b in bifurcacoes)
        if not existe:
            bifurcacoes.append({
                'id_trecho_atual': id_trecho_atual,
                'trechos_conectados': trechos_conectados,
                'ponto_final_chave': ponto_final_chave
            })
        return None
#---------------------------------------------------------------------------------------------
def identificar_ps(camada_rede):
    pontos_finais = {}
    trechos_sem_conexao = []
    
    for feature in camada_rede.getFeatures():
        geom = feature.geometry()
        if geom.isMultipart():
            vertices = geom.asMultiPolyline()[0]
        else:
            vertices = geom.asPolyline()
        
        if len(vertices) < 2:
            continue  
   
        ponto_final = QgsPoint(vertices[-1])
        ponto_final_chave = (ponto_final.x(), ponto_final.y())
        pontos_finais[ponto_final_chave] = feature.id()
    
    for feature in camada_rede.getFeatures():
        geom = feature.geometry()
        if geom.isMultipart():
            vertices = geom.asMultiPolyline()[0]
        else:
            vertices = geom.asPolyline()
        
        if len(vertices) < 2:
            continue
        ponto_inicial = QgsPoint(vertices[0])
        ponto_inicial_chave = (ponto_inicial.x(), ponto_inicial.y())
        
        if ponto_inicial_chave not in pontos_finais:
            trechos_sem_conexao.append(feature.id())
    
    return trechos_sem_conexao
#---------------------------------------------------------------------------------------------    
def Obter_compr_coletor(camada_rede, trecho_inicial):
    id_trecho_atual = trecho_inicial
    L_coletor = 0
    caminho_coletor = []
    
    while id_trecho_atual is not None:
        trecho = camada_rede.getFeature(id_trecho_atual)
        if trecho["NOME"]:
            return L_coletor, caminho_coletor
        
        L_coletor += trecho["L"]
        caminho_coletor.append(id_trecho_atual)
        id_trecho_atual = encontrar_proximo_trecho(camada_rede, id_trecho_atual)
        
    return L_coletor, caminho_coletor

#---------------------------------------------------------------------------------------------    
def maior_coletor(camada_rede, trechos_ps):
    caminho_coletores = {}

    maior_comprimento = 0
    id_maior_comprimento = None
    
    for id in trechos_ps:
        comprimento, caminho = Obter_compr_coletor(camada_rede, id)
        caminho_coletores[id] = caminho
        
        if comprimento > maior_comprimento:
            maior_comprimento = comprimento
            id_maior_comprimento = id
    
    return id_maior_comprimento, caminho_coletores[id_maior_comprimento]

#---------------------------------------------------------------------------------------------   
def nomear_pvs_trecho(camada_pv, trecho, n_pv): 
    
    ponto_inicial = obter_ponto_inicial(trecho.geometry())
    ponto_final = obter_ponto_final(trecho.geometry())
    ###ERRO DEE GEOMETRIA
    # Processa o ponto inicial--------------
    pv_inicial = obter_pv_no_ponto(camada_pv, ponto_inicial)
    if pv_inicial:
        if not pv_inicial["NUM"]:
            pv_inicial["NUM"] = n_pv
            pv_inicial["NOME"] = n_pv
            camada_pv.updateFeature(pv_inicial)
        else:
            n_pv = pv_inicial["NUM"]
    
    # Processa o ponto final-------------------------
    pv_final = obter_pv_no_ponto(camada_pv, ponto_final)
    if pv_final:
        if not pv_final["NUM"]:
            pv_final["NUM"] = n_pv + 1
            pv_final["NOME"] = n_pv + 1
            camada_pv.updateFeature(pv_final)
            n_pv += 2
        else:
            n_pv += 1
            
    return n_pv  
#---------------------------------------------------------------------------------------------   
def renomear_trechos(camada_rede, camada_pv):
    camada_rede.startEditing()
    camada_pv.startEditing()
    
    n_pv = 1
    n_trecho = 1
    n_coletor = 1
    trechos_ps = []
    trechos_ps = identificar_ps(camada_rede)
    
    while trechos_ps:
        id_maior_coletor, caminho_coletor = maior_coletor(camada_rede, trechos_ps)
        
        for id in caminho_coletor:
            trecho = camada_rede.getFeature(id)
            trecho["COLETOR"] = n_coletor
            trecho["TRECHO"] = n_trecho
            trecho["NOME"] = f"{n_coletor}-{n_trecho}"
            camada_rede.updateFeature(trecho)
            
            n_pv = nomear_pvs_trecho(camada_pv, trecho, n_pv)
            
            
            n_trecho += 1
        
        n_coletor += 1
        n_trecho = 1
        trechos_ps.remove(id_maior_coletor)
    
    camada_pv.commitChanges()
    camada_rede.commitChanges()
    return 1
        
#---------------------------------------------------------------------------------------------   
def apagar_dados_colunas(camada_rede, camada_pv):
    camada_rede.startEditing()
    camada_pv.startEditing()
    
    if camada_rede and camada_pv.isValid():
        for feature in camada_pv.getFeatures():
            if 'NUM' in camada_pv.fields().names():
                camada_pv.changeAttributeValue(feature.id(), camada_pv.fields().indexFromName('NUM'), None)
            if 'NOME' in camada_pv.fields().names():
                camada_pv.changeAttributeValue(feature.id(), camada_pv.fields().indexFromName('NOME'), None)

    if camada_rede and camada_rede.isValid():
        for feature in camada_rede.getFeatures():
            if 'TRECHO' in camada_rede.fields().names():
                camada_rede.changeAttributeValue(feature.id(), camada_rede.fields().indexFromName('TRECHO'), None)
            if 'COLETOR' in camada_rede.fields().names():
                camada_rede.changeAttributeValue(feature.id(), camada_rede.fields().indexFromName('COLETOR'), None)
            if 'NOME' in camada_rede.fields().names():
                camada_rede.changeAttributeValue(feature.id(), camada_rede.fields().indexFromName('NOME'), None)

    camada_pv.commitChanges()
    camada_rede.commitChanges()

#---------------------------------------------------------------------------------------------   
def mostrar_avisos_bifurcacoes(camada_rede):
    if not bifurcacoes:
        return
    
    # Juntar todas as infos numa mensagem só
    mensagens = []
    todos_trechos_para_selecionar = set()
    
    for bif in bifurcacoes:
        id_atual = bif['id_trecho_atual']
        conectados = bif['trechos_conectados']
        ponto = bif['ponto_final_chave']
        x, y = ponto
        ids_str = ", ".join(str(tid) for tid in conectados)
        mensagens.append(
            f"Trecho id: {id_atual}\n"
            f"Trechos conectados id: {ids_str}\n"
            f"Coordenada PV: ({x:.3f}, {y:.3f})\n\n"
        )
        todos_trechos_para_selecionar.update(conectados)
    
    msg_final = "Foram encontradas bifurcações nos seguintes trechos:\n\n" + "\n---\n".join(mensagens)

    QMessageBox.critical(None, "Erros de Bifurcação", msg_final)
    
    # Selecionar todos os trechos com bifurcação
    camada_rede.selectByIds(list(todos_trechos_para_selecionar))
    
    # Dar zoom em todos juntos
    rect = QgsRectangle()
    primeiro = True
    for fid in todos_trechos_para_selecionar:
        feat = camada_rede.getFeature(fid)
        if primeiro:
            rect = feat.geometry().boundingBox()
            primeiro = False
        else:
            rect.combineExtentWith(feat.geometry().boundingBox())
    
    iface.mapCanvas().setExtent(rect)
    iface.mapCanvas().refresh()  
#---------------------------------------------------------------------------------------------   
           
def executar_nomeacao_automatica():

    global layer_rede, layer_pv, bifurcacoes
    bifurcacoes.clear()

    #------------------VERIFICAR EXISTENCIA DE CAMADAS-------------------------------
    camadas_verificar = ["PV", "REDE"]
    nao_encontradas = verificar_camadas(camadas_verificar)
    if nao_encontradas:
        mensagem = "Camadas não encontradas: " + ", ".join(nao_encontradas)
        iface.messageBar().pushMessage(
            "Erro", 
            mensagem,
            level=Qgis.Critical, 
            duration=7  
        )
        return
    #--------------------------------------------------------------------------------
    configuracoes = carregar_configuracoes()
    print(configuracoes)
    layer_pv = configuracoes.get("camada_pv") 
    layer_rede = configuracoes.get("camada_rede")
    camada_rede = QgsProject.instance().mapLayer(layer_rede)
    camada_pv = QgsProject.instance().mapLayer(layer_pv)
            
    if camada_pv and camada_rede:
               
        adicionar_colunas()
        apagar_dados_colunas(camada_rede, camada_pv)
        calcular_comprimento_rede()
        concluido  = renomear_trechos(camada_rede, camada_pv)
        mostrar_avisos_bifurcacoes(camada_rede)
        aplicar_estilo(layer_rede, "Estilo02_REDE.qml")

        if concluido == 1: 
            iface.messageBar().pushMessage(
                "Sucesso",
                "Trechos renomeados com sucesso!!!",
                level=Qgis.Success,
                duration=7
            )

        
        
        