# -*- coding: utf-8 -*-
#"""Gestão consumos de água e energia .ipynb

#Automatically generated by Colab.

#Original file is located at
#    https://colab.research.google.com/drive/1fJX0crNbizPgkaduCbeZ5xE5JEOQGTTN

#<img src="https://th.bing.com/th/id/R.a0f2fedcf441568ef0aab06aa35b5396?rik=fKm3Fa29AV3XCA&riu=http%3a%2f%2fwww.ipmaia.pt%2fSiteCollectionImages%2flogo_ipmaia_site_logo_ipmaia_small.png&ehk=V%2frBHqmSxtTv0TdlxudopfsjuG%2b5kbB8uHM58ZwCer4%3d&risl=&pid=ImgRaw&r=0" alt="Logo" width="250">

#Tenologia de Informação, Web e Multimédia

#Metodologias Ágeis de Desenvolvimento de Software
# Gestão de Consumo de Água, Energia e Gás

##Sobre o Projeto

#Este projeto tem como objetivo desenvolver um **monitoramento e gestão do consumo de água, energia elétrica e gás** em residências.

#Oferece as seguintes funcionalidades:

#-**Cadastro de residências** com informações detalhadas como localização (latitude e longitude), morada e certificado energético;

#**Registro de consumo mensal** de:
#  - Água (em **litros**),
#  - Energia (em **kWh**),
#  - Gás (em **m³**);

#**Associação de identificadores**:
#  - **CPE** (Código de Ponto de Energia),
#  - **CUI** (Código Universal de Instalação),
#  - **Contador de Água**;

#-**Geração de relatórios** detalhados por residência e um relatório geral com dados de consumo e custo;

#-**Verificação da integridade dos dados**, garantindo entradas válidas;


#**Data de inicio: 25/03/2025**

#**David Duarte, Wilker Lopes, Danilson Gonçalves, Rafael Fortes**

##Instalação de Bibliotecas

#Antes de iniciar o sistema, instalamos a biblioteca tabulate, que será usada para exibir os relatórios em formato de tabela, de forma organizada e legível.

#!pip install tabulate
import pandas as pd
from datetime import datetime
from tabulate import tabulate

##Classe Casa

#Esta classe representa uma residência no sistema. Ao criar uma nova instância, ela armazena:

#- Informações de localização (latitude e longitude);
#- Morada (endereço completo);
#- Certificado energético;
#- Descrição da casa;
#- Registros de consumo de água, energia e gás.
#- Registrar novos consumos com unidade e custo;
#- Gerar os dados da casa em formato de relatório.

class Casa:
    def __init__(self, id, latitude, longitude, morada, certificado_energetico, descricao):
        self.id = id
        self.latitude = latitude
        self.longitude = longitude
        self.morada = morada
        self.certificado_energetico = certificado_energetico
        self.descricao = descricao
        self.consumo_agua = []
        self.consumo_energia = []
        self.consumo_gas = []

    def registrar_consumo(self, tipo, periodo, valor, custo):
        unidades = {'agua': 'L', 'energia': 'kWh', 'gas': 'm³'}
        if tipo not in unidades:
            print(f"Erro: Tipo de consumo '{tipo}' inválido!")
            return False

        lista = getattr(self, f'consumo_{tipo}')
        for c in lista:
            if c['Periodo'] == periodo:
                print(f"Erro: Já existe consumo de {tipo} para {periodo}")
                return False

        lista.append({
            'Periodo': periodo,
            'Valor': round(valor, 2),
            'Unidade': unidades[tipo],
            'Custo': round(custo, 2)
        })
        return True

    def total_por_tipo(self, tipo):
        lista = getattr(self, f'consumo_{tipo}')
        total_valor = sum(c['Valor'] for c in lista)
        total_custo = sum(c['Custo'] for c in lista)
        return total_valor, total_custo

    def periodo_maior_gasto(self, tipo):
        lista = getattr(self, f'consumo_{tipo}')
        if not lista:
            return "Nenhum"
        maior = max(lista, key=lambda x: x['Custo'])
        return maior['Periodo']

    def gerar_relatorio(self):
        info = [
            ["ID", self.id],
            ["Descrição", self.descricao],
            ["Morada", self.morada],
            ["Certificado", self.certificado_energetico],
            ["Localização", f"{self.latitude}, {self.longitude}"]
        ]
        return info, self.consumo_agua, self.consumo_energia, self.consumo_gas

#Classe ControladorCasas

#É a classe que gerencia todas as casas cadastradas no sistema.

#Com ela é possível:
#- Adicionar novas casas com verificação de dados;
#- Registrar consumo mensal;
#- Listar os consumos de cada tipo por casa;
#- Gerar relatórios de cada residência;

class ControladorCasas:
    def __init__(self):
        self.casas = {}
        self.validador = Validador()
        self.tabelas = GeradorTabelas()

    def adicionar_casa(self, id, latitude, longitude, morada, certificado, descricao):
        if not self.validador.validar_casa(id, latitude, longitude, certificado):
            return False
        if id in self.casas:
            print(f"Erro: Casa {id} já existe!")
            return False
        self.casas[id] = Casa(id, latitude, longitude, morada, certificado, descricao)
        return True

    def registrar_consumo(self, id, tipo, periodo, valor, custo):
        if not self.validador.validar_consumo(tipo, periodo, valor, custo):
            print(f"Atenção: dados inválidos foram inseridos em {tipo.upper()} - {periodo}, mas serão registrados.")
        if id not in self.casas:
            print(f"Erro: Casa {id} não encontrada!")
            return False
        return self.casas[id].registrar_consumo(tipo, periodo, valor, custo)

    def listar_consumo(self, casa_id, tipo):
        if casa_id not in self.casas:
            print(f"Erro: Casa {casa_id} não encontrada!")
            return False
        consumos = getattr(self.casas[casa_id], f'consumo_{tipo}')
        self.tabelas.cabecalho(f"CONSUMO DE {tipo.upper()} - CASA {casa_id}")
        self.tabelas.tabela_consumo(consumos)
        return True

    def gerar_relatorio_geral(self):
        headers = ["ID", "Morada", "Certificado",
                   "Água (L)", "Custo Água (€)",
                   "Energia (kWh)", "Custo Energia (€)",
                   "Gás (m³)", "Custo Gás (€)"]
        linhas = []

        for casa in self.casas.values():
            agua_valor, agua_custo = casa.total_por_tipo('agua')
            energia_valor, energia_custo = casa.total_por_tipo('energia')
            gas_valor, gas_custo = casa.total_por_tipo('gas')

            linhas.append([
                casa.id,
                casa.morada,
                casa.certificado_energetico,
                f"{agua_valor:.2f}", f"{agua_custo:.2f}",
                f"{energia_valor:.2f}", f"{energia_custo:.2f}",
                f"{gas_valor:.2f}", f"{gas_custo:.2f}"
            ])

        print("\n" + "="*100)
        print("RELATÓRIO GERAL DE CONSUMOS".center(100))
        print("="*100)
        print(tabulate(linhas, headers=headers, tablefmt="grid"))

    def gerar_relatorio_individual(self):
        for casa in self.casas.values():
            info, agua, energia, gas = casa.gerar_relatorio()
            self.tabelas.cabecalho(f"RELATÓRIO DA CASA {casa.id}")
            self.tabelas.tabela_info_casa(info)

            for tipo_nome, dados in [('ÁGUA', agua), ('ENERGIA', energia), ('GÁS', gas)]:
                self.tabelas.cabecalho(f"CONSUMO DE {tipo_nome}")
                self.tabelas.tabela_consumo(dados)

            self.tabelas.cabecalho("PERÍODO DE MAIOR GASTO")
            print(f"Água: {casa.periodo_maior_gasto('agua')}")
            print(f"Energia: {casa.periodo_maior_gasto('energia')}")
            print(f"Gás: {casa.periodo_maior_gasto('gas')}")
            print()

    def verificar_integridade(self):
        print("\n" + "="*100)
        print("VERIFICAÇÃO DE INTEGRIDADE".center(100))
        print("="*100)
        problemas = 0

        for casa in self.casas.values():
            if casa.certificado_energetico not in ["A+", "A", "B", "B-", "C", "D", "E", "F", "G"]:
                print(f"[ERRO] Casa {casa.id}: Certificado energético inválido")
                problemas += 1

            for tipo in ['agua', 'energia', 'gas']:
                for c in getattr(casa, f'consumo_{tipo}'):
                    if c['Valor'] <= 0 or c['Custo'] <= 0:
                        print(f"[ERRO] Casa {casa.id} - {tipo.upper()} ({c['Periodo']}): Valor ou custo inválido")
                        problemas += 1

        if problemas == 0:
            print("✅ Todos os dados estão válidos e consistentes.")
        else:
            print(f"⚠️ Foram encontrados {problemas} problema(s) nos dados.")

class GeradorTabelas:
    @staticmethod
    def cabecalho(titulo, largura=100):
        print("\n" + "=" * largura)
        print(titulo.center(largura))
        print("=" * largura)

    @staticmethod
    def tabela_info_casa(info):
        print(tabulate(info, tablefmt="fancy_grid"))

    @staticmethod
    def tabela_consumo(consumos):
        if not consumos:
            print("Sem registros.")
            return

        dados = []
        for c in consumos:
            valor_str = f"{c['Valor']:.2f} {c['Unidade']}"
            custo_str = f"{c['Custo']:.2f} €"
            dados.append([c['Periodo'], valor_str, custo_str])

        print(tabulate(dados, headers=["Período", "Consumo", "Custo"], tablefmt="grid"))

class Validador:
    @staticmethod
    def validar_casa(id, latitude, longitude, certificado):
        if not id or not isinstance(id, str):
            print("Erro: ID inválido")
            return False
        if not (-90 <= latitude <= 90) or not (-180 <= longitude <= 180):
            print("Erro: Coordenadas inválidas")
            return False
        if certificado not in ["A+", "A", "B", "B-", "C", "D", "E", "F", "G"]:
            print(f"Erro: Certificado '{certificado}' inválido")
            return False
        return True

    @staticmethod
    def validar_consumo(tipo, periodo, valor, custo):
        if tipo not in ['agua', 'energia', 'gas']:
            print(f"Erro: Tipo '{tipo}' inválido")
            return False
        try:
            mes, ano = map(int, periodo.split("/"))
            if not (1 <= mes <= 12) or not (2000 <= ano <= 2100):
                raise ValueError
        except:
            print("Erro: Período inválido (use MM/AAAA)")
            return False
        if valor <= 0 or custo <= 0:
            return False
        return True

#if __name__ == '__main__':
    #main()
    #sistema = ControladorCasas()

    #sistema.adicionar_casa("001", 41.1578, -8.6299, "Rua do Porto 123", "A+", "Casa Central")
    #sistema.adicionar_casa("002", 41.1495, -8.6108, "Avenida da Liberdade 456", "B", "Apartamento")

    #sistema.registrar_consumo("001", "agua", "01/2025", 15000, 45.75)
    #sistema.registrar_consumo("001", "energia", "01/2025", 350, 120.50)
    #sistema.registrar_consumo("001", "gas", "01/2025", 12.5, 35.90)

    #sistema.registrar_consumo("002", "agua", "02/2025", 18000, 50.00)
    #sistema.registrar_consumo("002", "energia", "02/2025", 400, -130.00)
    #sistema.registrar_consumo("002", "gas", "02/2025", 14, -37.90)

    #Erros
    #sistema.registrar_consumo("001", "energia", "01/2025", -100, 100)
    #sistema.registrar_consumo("001", "gas", "01/2025", 10, -30)
    #sistema.adicionar_casa("001", 41.15, -8.62, "Rua da Liberdade", "A+", "Casa Principal")
    #sistema.adicionar_casa("002", 41.12, -8.63, "Rua das Flores", "B", "Casa Secundária")
    #sistema.adicionar_casa("003", 41.10, -8.60, "Rua dos Erros", "X", "Casa com Certificado Inválido")
    #sistema.adicionar_casa("004", 95.00, -200.00, "Coordenada Errada", "C", "Casa com Coordenadas Inválidas")
    #sistema.registrar_consumo("001", "agua", "01/2025", 10000, 50)
    #sistema.registrar_consumo("001", "energia", "01/2025", 300, 120)
    #sistema.registrar_consumo("001", "gas", "01/2025", 15, 40)

    #sistema.registrar_consumo("002", "agua", "01/2025", -5000, 25)
    #sistema.registrar_consumo("002", "energia", "01/2025", 350, -50)
    #sistema.registrar_consumo("002", "gas", "01/2025", 10, 0)
    #sistema.registrar_consumo("001", "agua", "13/2025", 5000, 30)
    #sistema.registrar_consumo("001", "madeira", "01/2025", 100, 20)
    #sistema.registrar_consumo("001", "agua", "01/2025", 20000, 100)

#sistema.gerar_relatorio_geral()

#sistema.gerar_relatorio_individual()

#sistema.listar_consumo("001", "energia")

#sistema.listar_consumo("001", "agua")

#sistema.listar_consumo("002", "gas")

#sistema.verificar_integridade()

