"""
Módulo de Gerenciamento de Banco de Dados para Noise Module
"""
import json
import os
import traceback
from datetime import datetime
from typing import List, Dict, Optional


class NoiseDatabase:
    def __init__(self, db_file: str = None):
        """
        Inicializa o banco de dados de ruído
        
        Args:
            db_file: Caminho para o arquivo JSON do banco de dados
        """
        if db_file is None:
            current_dir = os.path.dirname(os.path.abspath(__file__))
            self.db_file = os.path.join(current_dir, "noise_db.json")
        else:
            self.db_file = db_file
        
        self.data = self._load_data()
    
    def _load_data(self) -> Dict:
        """
        Carrega os dados do arquivo JSON
        
        Returns:
            Dicionário com os dados do banco
        """
        try:
            if os.path.exists(self.db_file):
                with open(self.db_file, 'r', encoding='utf-8') as f:
                    data = json.load(f)
                    # Verifica se o arquivo tem a estrutura correta
                    if isinstance(data, dict) and "test_history" in data:
                        return data
                    else:
                        # Arquivo antigo ou corrompido, recria estrutura
                        return {
                            "test_history": [],
                            "metadata": {
                                "created": datetime.now().strftime("%d-%m-%Y %H:%M"),
                                "version": "1.0"
                            }
                        }
            else:
                # Arquivo não existe, cria estrutura inicial
                return {
                    "test_history": [],
                    "metadata": {
                        "created": datetime.now().strftime("%d-%m-%Y %H:%M"),
                        "version": "1.0"
                    }
                }
        except (json.JSONDecodeError, IOError) as e:
            print(f"Erro ao carregar banco de dados de ruído: {e}")
            return {
                "test_history": [],
                "metadata": {
                    "created": datetime.now().strftime("%d-%m-%Y %H:%M"),
                    "version": "1.0"
                }
            }
    
    def _save_data(self) -> bool:
        """
        Salva os dados no arquivo JSON
        
        Returns:
            True se salvou com sucesso, False caso contrário
        """
        try:
            # Atualiza metadata
            self.data["metadata"]["last_modified"] = datetime.now().strftime("%d-%m-%Y %H:%M")
            
            with open(self.db_file, 'w', encoding='utf-8') as f:
                json.dump(self.data, f, indent=2, ensure_ascii=False)
            return True
        except Exception as e:
            print(f"Erro ao salvar banco de dados de ruído: {e}")
            return False
    
    # Métodos para histórico de testes
    def get_test_history(self) -> List[Dict]:
        """
        Retorna o histórico de testes de ruído
        
        Returns:
            Lista com o histórico de testes
        """
        # Recarrega dados do arquivo para garantir sincronização
        self.data = self._load_data()
        return self.data.get("test_history", [])
    
    def add_test_to_history(self, test_data: Dict) -> bool:
        """
        Adiciona um teste de ruído ao histórico preservando testes anteriores
        
        Args:
            test_data: Dados do teste
            
        Returns:
            True se adicionou com sucesso, False caso contrário
        """
        if "test_history" not in self.data:
            self.data["test_history"] = []
        
        # Gera ID único sequencial para o novo teste
        existing_ids = [test.get("id", 0) for test in self.data["test_history"]]
        test_id = max(existing_ids, default=0) + 1
        test_data["id"] = test_id
        
        # Adiciona timestamp se não existir
        if "timestamp" not in test_data:
            test_data["timestamp"] = datetime.now().strftime("%d-%m-%Y %H:%M")
        
        # Adiciona o novo teste ao histórico (preservando os anteriores)
        self.data["test_history"].append(test_data)
        return self._save_data()
    
    def update_test_in_history(self, test_id: int, test_data: Dict) -> bool:
        """
        Atualiza um teste no histórico
        
        Args:
            test_id: ID do teste
            test_data: Novos dados do teste
            
        Returns:
            True se atualizou com sucesso, False caso contrário
        """
        try:
            # Busca o teste pelo ID
            for i, test in enumerate(self.data["test_history"]):
                if test.get("id") == test_id:
                    # Preserva timestamp original se não fornecido
                    if "timestamp" not in test_data:
                        test_data["timestamp"] = test.get("timestamp", "")
                    
                    # Atualiza o teste
                    test_data["id"] = test_id
                    self.data["test_history"][i] = test_data
                    return self._save_data()
            
            print(f"⚠️ Teste com ID {test_id} não encontrado no histórico")
            return False
        except Exception as e:
            print(f"❌ Erro ao atualizar teste no histórico: {e}")
            return False
    
    def delete_test_from_history(self, test_id: int) -> bool:
        """
        Remove um teste específico do histórico
        
        Args:
            test_id: ID do teste
            
        Returns:
            True se removeu com sucesso, False caso contrário
        """
        try:
            # Busca e remove o teste pelo ID
            original_count = len(self.data["test_history"])
            self.data["test_history"] = [
                test for test in self.data["test_history"] 
                if test.get("id") != test_id
            ]
            
            if len(self.data["test_history"]) < original_count:
                print(f"🗑️ Teste {test_id} removido do histórico de ruído")
                return self._save_data()
            else:
                print(f"⚠️ Teste com ID {test_id} não encontrado no histórico")
                return False
        except Exception as e:
            print(f"❌ Erro ao remover teste do histórico de ruído: {e}")
            return False
    
    def clear_test_history(self) -> bool:
        """
        Remove todos os testes do histórico
        
        Returns:
            True se removeu com sucesso, False caso contrário
        """
        try:
            self.data["test_history"] = []
            print("🗑️ Histórico de testes de ruído limpo")
            return self._save_data()
        except Exception as e:
            print(f"❌ Erro ao limpar histórico de testes de ruído: {e}")
            return False
    
    def get_test_by_id(self, test_id: int) -> Optional[Dict]:
        """
        Busca um teste específico por ID
        
        Args:
            test_id: ID do teste
            
        Returns:
            Dicionário com os dados do teste ou None se não encontrado
        """
        # Busca o teste pelo ID
        for test in self.data.get("test_history", []):
            if test.get("id") == test_id:
                return test
        return None
    
    def get_tests_by_date_range(self, start_date: str, end_date: str) -> List[Dict]:
        """
        Busca testes em um intervalo de datas
        
        Args:
            start_date: Data inicial (formato: YYYY-MM-DD)
            end_date: Data final (formato: YYYY-MM-DD)
            
        Returns:
            Lista com os testes no intervalo de datas
        """
        try:
            start_dt = datetime.strptime(start_date, "%Y-%m-%d")
            end_dt = datetime.strptime(end_date, "%Y-%m-%d")
            
            filtered_tests = []
            for test in self.data.get("test_history", []):
                try:
                    test_dt = datetime.strptime(test.get("timestamp", "")[:10], "%Y-%m-%d")
                    if start_dt <= test_dt <= end_dt:
                        filtered_tests.append(test)
                except:
                    continue
            
            return filtered_tests
        except Exception as e:
            print(f"Erro ao filtrar testes por data: {e}")
            return []
    
    def get_statistics(self) -> Dict:
        """
        Retorna estatísticas dos testes
        
        Returns:
            Dicionário com estatísticas
        """
        tests = self.data.get("test_history", [])
        if not tests:
            return {
                "total_tests": 0,
                "total_duration": 0,
                "avg_noise_level": 0,
                "min_noise_level": 0,
                "max_noise_level": 0
            }
        
        total_duration = sum(test.get("duration", 0) for test in tests)
        all_noise_levels = []
        
        for test in tests:
            noise_data = test.get("noise_data", {})
            if isinstance(noise_data, dict):
                # Suporte para nova estrutura de dados
                if noise_data and isinstance(list(noise_data.values())[0], dict):
                    # Nova estrutura: {time: {"value": noise_value, "absolute_time": "HH:MM:SS"}}
                    noise_values = [v["value"] for v in noise_data.values() if isinstance(v, dict) and "value" in v]
                else:
                    # Estrutura antiga: {time: noise_value}
                    noise_values = list(noise_data.values())
                all_noise_levels.extend(noise_values)
        
        if all_noise_levels:
            avg_noise = sum(all_noise_levels) / len(all_noise_levels)
            min_noise = min(all_noise_levels)
            max_noise = max(all_noise_levels)
        else:
            avg_noise = min_noise = max_noise = 0
        
        return {
            "total_tests": len(tests),
            "total_duration": total_duration,
            "avg_noise_level": round(avg_noise, 2),
            "min_noise_level": round(min_noise, 2),
            "max_noise_level": round(max_noise, 2)
        }
    
    def export_test_data(self, test_id: int, export_format: str = "json") -> Optional[str]:
        """
        Exporta dados de um teste específico
        
        Args:
            test_id: ID do teste
            export_format: Formato de exportação (json, csv)
            
        Returns:
            String com os dados exportados ou None se erro
        """
        test = self.get_test_by_id(test_id)
        if not test:
            return None
        
        if export_format.lower() == "json":
            return json.dumps(test, indent=2, ensure_ascii=False)
        elif export_format.lower() == "csv":
            # Implementar exportação CSV se necessário
            return None
        else:
            return None
    
    def backup_database(self, backup_path: str = None) -> bool:
        """
        Cria backup do banco de dados
        
        Args:
            backup_path: Caminho para o backup
            
        Returns:
            True se backup criado com sucesso, False caso contrário
        """
        try:
            if backup_path is None:
                current_dir = os.path.dirname(os.path.abspath(__file__))
                timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
                backup_path = os.path.join(current_dir, f"noise_db_backup_{timestamp}.json")
            
            with open(backup_path, 'w', encoding='utf-8') as f:
                json.dump(self.data, f, indent=2, ensure_ascii=False)
            
            print(f"✅ Backup criado em: {backup_path}")
            return True
        except Exception as e:
            print(f"❌ Erro ao criar backup: {e}")
            return False
    
    def migrate_old_data(self):
        """
        Migra dados antigos para o novo formato com max_noise_time
        """
        try:
            migrated_count = 0
            for test in self.data.get("test_history", []):
                # Verifica se o teste já tem max_noise_time
                if "max_noise_time" not in test:
                    # Calcula max_noise_time para dados antigos
                    noise_data = test.get("noise_data", {})
                    if isinstance(noise_data, dict) and noise_data:
                        # Para dados antigos, usa "-" como padrão
                        test["max_noise_time"] = "-"
                        migrated_count += 1
            
            if migrated_count > 0:
                print(f"🔄 Migrados {migrated_count} testes antigos para novo formato")
                self._save_data()
            else:
                print("✅ Dados já estão no formato atual")
                
        except Exception as e:
            print(f"❌ Erro durante migração: {e}")
            traceback.print_exc()
