# -*- 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
from PyQt5.QtCore import QVariant, QTimer
from PyQt5.QtWidgets import QMessageBox, QWidget  
from qgis.gui import QgsMapToolIdentifyFeature
from qgis.utils import iface
from qgis.core import QgsPoint

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

layer_pv = ""
layer_rede = ""
N_PV_Final = 0
N_PV = 0
coletor = 0


def msg_box(titulo, mensagem):
    msg = QMessageBox()
    msg.setIcon(QMessageBox.Warning) 
    msg.setWindowTitle(titulo) 
    msg.setText(mensagem) 
    msg.setStandardButtons(QMessageBox.Ok) 
    msg.exec_()  

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.01:  # Pequena margem de tolerância
            return pv
    return None

def nomear_pvs_trecho(camada_pv, trecho, proximo_pv):
   
    ponto_inicial = obter_ponto_inicial(trecho.geometry())
    ponto_final = obter_ponto_final(trecho.geometry())
    global N_PV_Final
    camada_pv.startEditing()
    
    # 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"] = proximo_pv
            camada_pv.updateFeature(pv_inicial)
        else:
            proximo_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"] = proximo_pv + 1
            camada_pv.updateFeature(pv_final)
            proximo_pv = proximo_pv + 2
            N_PV_Final = proximo_pv
            
        else:
            N_PV_Final = proximo_pv + 1
            proximo_pv = pv_final["NUM"]
    
    camada_pv.commitChanges()
    return proximo_pv

def verificar_conectividade(camada_rede, trecho_inicial):
    """Verifica se todos os trechos selecionados estão conectados entre si."""
    visitados = set()
    fila = [trecho_inicial]

    while fila:
        trecho = fila.pop(0)
        visitados.add(trecho.id())

        ponto_final = obter_ponto_final(trecho.geometry())

        for t in camada_rede.getFeatures():
            if t.id() in visitados:
                continue

            ponto_inicial = obter_ponto_inicial(t.geometry())
            if ponto_inicial == ponto_final:
                fila.append(t)

    selecionados = {f.id() for f in camada_rede.selectedFeatures()}

    if not selecionados.issubset(visitados):
        msg_box("Erro", "Os trechos selecionados não estão todos no mesmo coletor.")
        return False

    return True

def encontrar_proximo_trecho(camada_rede, ponto_final_atual, visitados):
    """Encontra o próximo trecho conectado ao ponto final atual."""
    for trecho in camada_rede.getFeatures():
        if trecho.id() in visitados:
            continue

        ponto_inicial_trecho = obter_ponto_inicial(trecho.geometry())
        if ponto_inicial_trecho and ponto_inicial_trecho == ponto_final_atual:
            return trecho

    return None

def percorrer_fluxo_rede(camada_pv, camada_rede, trecho_inicial):
    """Percorre os trechos nomeando-os e também nomeia os PVs correspondentes."""
    if not trecho_inicial:
        return

    if not verificar_conectividade(camada_rede, trecho_inicial):
        return

    visitados = []  # Lista de IDs visitados
    corrente = trecho_inicial
    visitados.append(corrente.id())
#-------------------------------------------------
    global coletor, N_PV  
    coletor = int(coletor)
    proximo_pv = int(N_PV)
    trecho_num = 1
#--------------------------------------------------
    camada_rede.startEditing()
    
    while corrente:
        if corrente["NOME"]:
            break

        corrente["COLETOR"] = coletor
        corrente["TRECHO"] = trecho_num
        corrente["NOME"] = f"{coletor} - {trecho_num}"
        camada_rede.updateFeature(corrente)
        
        # Mantém selecionado o trecho modificado
        camada_rede.select(corrente.id())

        # Nomeia os PVs do trecho e atualiza o próximo número a ser usado
        proximo_pv = nomear_pvs_trecho(camada_pv, corrente, proximo_pv)

        ponto_final_atual = obter_ponto_final(corrente.geometry())
        corrente = encontrar_proximo_trecho(camada_rede, ponto_final_atual, visitados)

        if corrente:
            visitados.append(corrente.id())

        trecho_num += 1
        N_PV = proximo_pv
    camada_rede.commitChanges()

def verificar_trecho_entrada(camada_rede, trecho):
    """Verifica se o trecho é o primeiro trecho do coletor."""
    ponto_inicial_trecho = obter_ponto_inicial(trecho.geometry())

    for outro_trecho in camada_rede.getFeatures():
        if outro_trecho.id() == trecho.id():
            continue

        ponto_final_outro_trecho = obter_ponto_final(outro_trecho.geometry())
        if ponto_final_outro_trecho == ponto_inicial_trecho:
            return False

    return True

def capturar_feicao(camada_pv, camada_rede, dlg):
    """Ativa a ferramenta de captura de feição no QGIS para iniciar a nomeação."""
    if not camada_rede or not camada_pv:
        return

    if not camada_rede.isValid() or not camada_pv.isValid():
        return
    
    # Limpa a seleção antes de iniciar, para que apenas os trechos identificados fiquem selecionados
    camada_rede.removeSelection()

    ferramenta_identificar = QgsMapToolIdentifyFeature(iface.mapCanvas())
    ferramenta_identificar.setLayer(camada_rede)

    def capturar_evento(feature):
        global coletor, N_PV_Final
        if not verificar_trecho_entrada(camada_rede, feature):
            msg_box("SELEÇÃO INVÁLIDA!!", "O trecho selecionado não é o primeiro trecho do coletor.")
            return

        percorrer_fluxo_rede(camada_pv, camada_rede, feature)
        iface.mapCanvas().unsetMapTool(ferramenta_identificar)
        coletor += 1
        dlg.Edit_Ncoletor.setValue(int(coletor))
        dlg.Edit_Npv.setValue(int(N_PV_Final))
    ferramenta_identificar.featureIdentified.connect(capturar_evento)
    iface.mapCanvas().setMapTool(ferramenta_identificar)


def executar_nomear_trechos(dlg):
    configuracoes = carregar_configuracoes()
    global layer_rede, layer_pv, coletor, N_PV
    
    #------------------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)
        messageBar = iface.messageBar()
        progressMessageBar = messageBar.createMessage(mensagem)
        widget_ref = messageBar.pushWidget(progressMessageBar, Qgis.Critical)
        QTimer.singleShot(7000, lambda: messageBar.popWidget(widget_ref))
        raise QgsProcessingException("Execução interrompida: Existem ausências de camadas")
    #--------------------------------------------------------------------------------
    camada_pv = configuracoes.get("camada_pv") 
    camada_rede = configuracoes.get("camada_rede")
            
    if camada_pv and camada_rede:
        adicionar_colunas()
        coletor = dlg.Edit_Ncoletor.text()
        N_PV = dlg.Edit_Npv.text()
        capturar_feicao(camada_pv, camada_rede, dlg)

