import pandas as pd
import numpy as np
import joblib
import os
import warnings
warnings.filterwarnings('ignore')

class PreditorInteligente:
    def __init__(self):
        self.tipos_guia = {
            1: 'Internação',
            2: 'SADT',
            3: 'Consulta',
            4: 'Honorários',
            5: 'Odonto'
        }
        self.modelos_disponiveis = {}
        self.estatisticas = {}
        
    def carregar_modelos(self):
        """Carrega todos os modelos disponíveis"""
        print("🔍 Procurando modelos disponíveis...")
        
        # Modelo geral
        if os.path.exists('modelo_export_guias_2025-07-05_23-04-07.pkl'):
            self.modelos_disponiveis['geral'] = 'modelo_export_guias_2025-07-05_23-04-07.pkl'
            print("   ✅ Modelo geral encontrado")
        
        # Modelos por tipo
        for tipo, nome in self.tipos_guia.items():
            # Padrão: modelo_*_tipo{N}.pkl
            import glob
            arquivos = glob.glob(f'modelo_*_tipo{tipo}.pkl')
            if arquivos:
                self.modelos_disponiveis[f'tipo_{tipo}'] = arquivos[0]
                print(f"   ✅ Modelo {nome} encontrado: {arquivos[0]}")
        
        # Modelo avançado de consulta
        if os.path.exists('modelo_consulta_avancado.pkl'):
            self.modelos_disponiveis['consulta_avancado'] = 'modelo_consulta_avancado.pkl'
            print("   ✅ Modelo avançado de Consulta encontrado")
        
        if not self.modelos_disponiveis:
            print("❌ Nenhum modelo encontrado! Treine os modelos primeiro.")
            return False
        
        return True
    
    def analisar_arquivo(self, arquivo_csv, sep=';', encoding='utf-8-sig'):
        """Analisa o arquivo e identifica tipos de guia"""
        print(f"\n📂 Analisando arquivo: {arquivo_csv}")
        
        # Detecta cabeçalho
        with open(arquivo_csv, 'r', encoding=encoding) as f:
            primeira_linha = f.readline().strip()
        
        if primeira_linha and primeira_linha[0].isdigit():
            print("   ⚠️  Arquivo sem cabeçalho detectado")
            colunas = ['id', 'protocolo', 'id_usuario', 'id_convenio', 'tipo_guia', 
                      'data_cirurgia', 'data_cadastro', 'data_envio_operadora', 
                      'id_local', 'recem_nascido', 'tipo_atendimento', 'tipo_acomodacao', 
                      'id_cod', 'cod', 'via_acesso', 'quantidade', 'glosado']
            
            # Ajusta para arquivos com menos colunas
            df_teste = pd.read_csv(arquivo_csv, sep=sep, encoding=encoding, nrows=1)
            colunas = colunas[:len(df_teste.columns)]
            
            df = pd.read_csv(arquivo_csv, sep=sep, encoding=encoding, header=None, names=colunas)
        else:
            df = pd.read_csv(arquivo_csv, sep=sep, encoding=encoding)
        
        print(f"   • Total de registros: {len(df):,}")
        
        # Analisa distribuição por tipo
        if 'tipo_guia' in df.columns:
            dist_tipos = df['tipo_guia'].value_counts().sort_index()
            print("\n📊 Distribuição por tipo de guia:")
            
            for tipo, count in dist_tipos.items():
                if tipo in self.tipos_guia:
                    nome = self.tipos_guia[tipo]
                    perc = count / len(df) * 100
                    print(f"   • {nome} (Tipo {tipo}): {count:,} ({perc:.1f}%)")
                    self.estatisticas[tipo] = {'count': count, 'percentual': perc}
        
        return df
    
    def preparar_dados_basico(self, df):
        """Preparação básica comum a todos os modelos"""
        # Datas
        for col in ['data_cadastro', 'data_cirurgia', 'data_envio_operadora']:
            if col in df.columns:
                df[col] = pd.to_datetime(df[col], errors='coerce')
        
        # Features temporais
        if 'data_envio_operadora' in df.columns and 'data_cadastro' in df.columns:
            df['dias_envio'] = (df['data_envio_operadora'] - df['data_cadastro']).dt.days
            df['dias_envio'] = df['dias_envio'].fillna(5)
        else:
            df['dias_envio'] = 5
        
        if 'data_cirurgia' in df.columns and 'data_cadastro' in df.columns:
            df['dias_ate_cirurgia'] = (df['data_cirurgia'] - df['data_cadastro']).dt.days
            df['dias_ate_cirurgia'] = df['dias_ate_cirurgia'].fillna(0)
        else:
            df['dias_ate_cirurgia'] = 0
        
        if 'data_cirurgia' in df.columns:
            df['mes_cirurgia'] = df['data_cirurgia'].dt.month
            df['dia_semana_cirurgia'] = df['data_cirurgia'].dt.dayofweek
            df['mes_cirurgia'] = df['mes_cirurgia'].fillna(6)
            df['dia_semana_cirurgia'] = df['dia_semana_cirurgia'].fillna(3)
        else:
            df['mes_cirurgia'] = 6
            df['dia_semana_cirurgia'] = 3
        
        # Procedimentos combinados
        if 'procedimentos_combinados' in df.columns:
            df['procedimentos_combinados'] = df['procedimentos_combinados'].fillna('').astype(str).str.count(',') + 1
            df.loc[df['procedimentos_combinados'] == 1, 'procedimentos_combinados'] = 0
        
        return df
    
    def predizer_com_modelo_geral(self, df, arquivo_saida):
        """Usa o modelo geral para todos os tipos"""
        print("\n🤖 Usando modelo geral...")
        
        model_info = joblib.load(self.modelos_disponiveis['geral'])
        model = model_info['model']
        encoders = model_info['encoders']
        best_threshold = model_info['best_threshold']
        feature_names = model_info['feature_names']
        
        # Prepara dados
        df = self.preparar_dados_basico(df.copy())
        
        # Codifica categóricas
        for col, encoder in encoders.items():
            if col in df.columns:
                df[col] = df[col].fillna('Unknown').astype(str)
                try:
                    df[col] = encoder.transform(df[col])
                except:
                    df[col] = df[col].apply(lambda x: encoder.transform([x])[0] 
                                           if x in encoder.classes_ else 0)
        
        # Remove glosado se existir
        if 'glosado' in df.columns:
            df_pred = df.drop('glosado', axis=1)
        else:
            df_pred = df
        
        # Prepara features
        X = df_pred[feature_names].copy()
        
        # Garante features numéricas
        for col in X.columns:
            if X[col].dtype == 'object':
                X[col] = pd.to_numeric(X[col], errors='coerce').fillna(0)
        
        # Predições
        probabilidades = model.predict_proba(X)[:, 1]
        predicoes = (probabilidades >= best_threshold).astype(int)
        
        # Resultado
        resultado = pd.DataFrame({
            'id': df['id'],
            'protocolo': df['protocolo'],
            'tipo_guia': df['tipo_guia'] if 'tipo_guia' in df.columns else 0,
            'id_convenio': df['id_convenio'],
            'id_cod': df['id_cod'],
            'cod': df['cod'],
            'probabilidade_glosa': probabilidades,
            'predicao_glosa': predicoes,
            'nivel_risco': pd.cut(probabilidades, 
                                 bins=[0, 0.3, 0.5, 0.7, 1.0],
                                 labels=['Baixo', 'Médio', 'Alto', 'Muito Alto'])
        })
        
        resultado.to_csv(arquivo_saida, index=False, sep=';')
        return resultado, probabilidades, predicoes
    
    def predizer_com_modelo_especifico(self, df, tipo, arquivo_saida):
        """Usa modelo específico do tipo"""
        nome_tipo = self.tipos_guia[tipo]
        print(f"\n🤖 Usando modelo específico para {nome_tipo}...")
        
        modelo_arquivo = self.modelos_disponiveis.get(f'tipo_{tipo}')
        if not modelo_arquivo:
            print(f"   ⚠️  Modelo específico não encontrado, usando modelo geral")
            return self.predizer_com_modelo_geral(df, arquivo_saida)
        
        model_info = joblib.load(modelo_arquivo)
        model = model_info['model']
        encoders = model_info['encoders']
        best_threshold = model_info['best_threshold']
        feature_names = model_info['feature_names']
        
        # Filtra apenas o tipo
        df_tipo = df[df['tipo_guia'] == tipo].copy()
        
        # Prepara dados
        df_tipo = self.preparar_dados_basico(df_tipo)
        
        # Codifica categóricas
        for col, encoder in encoders.items():
            if col in df_tipo.columns:
                df_tipo[col] = df_tipo[col].fillna('Unknown').astype(str)
                try:
                    df_tipo[col] = encoder.transform(df_tipo[col])
                except:
                    df_tipo[col] = 0
        
        # Remove glosado se existir
        if 'glosado' in df_tipo.columns:
            df_pred = df_tipo.drop('glosado', axis=1)
        else:
            df_pred = df_tipo
        
        # Prepara features
        X = df_pred[feature_names].copy()
        
        # Garante features numéricas
        for col in X.columns:
            if X[col].dtype == 'object':
                X[col] = pd.to_numeric(X[col], errors='coerce').fillna(0)
        
        # Predições
        probabilidades = model.predict_proba(X)[:, 1]
        predicoes = (probabilidades >= best_threshold).astype(int)
        
        # Resultado
        resultado = pd.DataFrame({
            'id': df_tipo['id'],
            'protocolo': df_tipo['protocolo'],
            'tipo_guia': tipo,
            'tipo_nome': nome_tipo,
            'id_convenio': df_tipo['id_convenio'],
            'id_cod': df_tipo['id_cod'],
            'cod': df_tipo['cod'],
            'probabilidade_glosa': probabilidades,
            'predicao_glosa': predicoes,
            'nivel_risco': pd.cut(probabilidades, 
                                 bins=[0, 0.3, 0.5, 0.7, 1.0],
                                 labels=['Baixo', 'Médio', 'Alto', 'Muito Alto'])
        })
        
        # Salva resultado específico
        arquivo_tipo = arquivo_saida.replace('.csv', f'_{nome_tipo.lower()}.csv')
        resultado.to_csv(arquivo_tipo, index=False, sep=';')
        print(f"   💾 Salvo: {arquivo_tipo}")
        
        return resultado, probabilidades, predicoes
    
    def executar(self, arquivo_csv):
        """Executa predição inteligente"""
        print("\n" + "="*60)
        print("🧠 PREDITOR INTELIGENTE DE GLOSAS")
        print("="*60)
        
        # Carrega modelos disponíveis
        if not self.carregar_modelos():
            return
        
        # Analisa arquivo
        df = self.analisar_arquivo(arquivo_csv)
        
        # Nome base para arquivos de saída
        nome_base = os.path.splitext(arquivo_csv)[0]
        
        # Estratégia de predição
        print("\n📋 Estratégia de predição:")
        
        resultados_finais = []
        estatisticas_finais = {}
        
        # Se há múltiplos tipos e modelos específicos disponíveis
        tipos_presentes = [t for t in self.estatisticas.keys() if self.estatisticas[t]['count'] > 0]
        
        if len(tipos_presentes) > 1:
            print("   • Múltiplos tipos detectados")
            print("   • Aplicando modelos específicos quando disponíveis")
            
            for tipo in tipos_presentes:
                if f'tipo_{tipo}' in self.modelos_disponiveis:
                    # Usa modelo específico
                    df_tipo = df[df['tipo_guia'] == tipo]
                    resultado, probs, preds = self.predizer_com_modelo_especifico(
                        df_tipo, tipo, f"{nome_base}_predicoes.csv"
                    )
                    resultados_finais.append(resultado)
                    
                    estatisticas_finais[self.tipos_guia[tipo]] = {
                        'total': len(resultado),
                        'glosados': preds.sum(),
                        'taxa': preds.mean() * 100,
                        'score_medio': probs.mean()
                    }
                else:
                    # Usa modelo geral para este tipo
                    df_tipo = df[df['tipo_guia'] == tipo]
                    resultado, probs, preds = self.predizer_com_modelo_geral(
                        df_tipo, f"{nome_base}_predicoes_{self.tipos_guia[tipo].lower()}.csv"
                    )
                    resultados_finais.append(resultado)
                    
                    estatisticas_finais[self.tipos_guia[tipo]] = {
                        'total': len(resultado),
                        'glosados': preds.sum(),
                        'taxa': preds.mean() * 100,
                        'score_medio': probs.mean()
                    }
        else:
            # Tipo único - usa modelo específico se disponível
            tipo_unico = tipos_presentes[0]
            nome_tipo = self.tipos_guia[tipo_unico]
            
            # Verifica se é consulta e tem modelo avançado
            if tipo_unico == 3 and 'consulta_avancado' in self.modelos_disponiveis:
                print(f"   • Tipo único: {nome_tipo}")
                print("   • Usando modelo AVANÇADO de consulta")
                
                # Importa e executa o preditor avançado
                from predizer_consulta_avancado import predizer_consulta_avancado
                resultado = predizer_consulta_avancado(arquivo_csv)
                
                if resultado is not None:
                    estatisticas_finais[nome_tipo] = {
                        'total': len(resultado),
                        'glosados': resultado['predicao_glosa'].sum(),
                        'taxa': resultado['predicao_glosa'].mean() * 100,
                        'score_medio': resultado['probabilidade_glosa'].mean()
                    }
                return
            
            elif f'tipo_{tipo_unico}' in self.modelos_disponiveis:
                print(f"   • Tipo único: {nome_tipo}")
                print(f"   • Usando modelo específico")
                resultado, probs, preds = self.predizer_com_modelo_especifico(
                    df, tipo_unico, f"{nome_base}_predicoes.csv"
                )
            else:
                print(f"   • Tipo único: {nome_tipo}")
                print("   • Usando modelo geral")
                resultado, probs, preds = self.predizer_com_modelo_geral(
                    df, f"{nome_base}_predicoes.csv"
                )
            
            estatisticas_finais[nome_tipo] = {
                'total': len(resultado),
                'glosados': preds.sum(),
                'taxa': preds.mean() * 100,
                'score_medio': probs.mean()
            }
        
        # Consolida resultados se múltiplos tipos
        if len(resultados_finais) > 1:
            print("\n📊 Consolidando resultados...")
            resultado_final = pd.concat(resultados_finais, ignore_index=True)
            resultado_final.to_csv(f"{nome_base}_predicoes_completo.csv", index=False, sep=';')
            print(f"   💾 Arquivo consolidado: {nome_base}_predicoes_completo.csv")
        
        # Relatório final
        print("\n" + "="*60)
        print("📊 RESUMO FINAL DAS PREDIÇÕES")
        print("="*60)
        
        total_geral = sum(stat['total'] for stat in estatisticas_finais.values())
        total_glosados = sum(stat['glosados'] for stat in estatisticas_finais.values())
        
        print(f"\n📈 Estatísticas Gerais:")
        print(f"   • Total de guias analisadas: {total_geral:,}")
        print(f"   • Total previsto como glosado: {total_glosados:,} ({total_glosados/total_geral*100:.1f}%)")
        
        print(f"\n📊 Por Tipo de Guia:")
        for tipo_nome, stats in estatisticas_finais.items():
            print(f"\n   {tipo_nome}:")
            print(f"   • Analisadas: {stats['total']:,}")
            print(f"   • Glosadas: {stats['glosados']} ({stats['taxa']:.1f}%)")
            print(f"   • Score médio: {stats['score_medio']:.3f}")
        
        # Recomendações finais
        print("\n" + "="*60)
        print("💡 RECOMENDAÇÕES AUTOMÁTICAS")
        print("="*60)
        
        for tipo_nome, stats in estatisticas_finais.items():
            if stats['taxa'] > 20:
                print(f"\n🔴 {tipo_nome}: Alta taxa de glosa prevista ({stats['taxa']:.1f}%)")
                print("   → Revisar processos e documentação")
            elif stats['taxa'] > 10:
                print(f"\n🟡 {tipo_nome}: Taxa moderada de glosa ({stats['taxa']:.1f}%)")
                print("   → Atenção aos casos de alto risco")
            else:
                print(f"\n🟢 {tipo_nome}: Baixa taxa de glosa ({stats['taxa']:.1f}%)")
                print("   → Manter práticas atuais")
        
        print("\n✅ Análise concluída!")


# Execução principal
if __name__ == "__main__":
    import sys
    
    if len(sys.argv) > 1:
        arquivo = sys.argv[1]
        preditor = PreditorInteligente()
        preditor.executar(arquivo)
    else:
        print("❌ Uso: python predizer_inteligente.py <arquivo.csv>")
        print("\n📌 Este script detecta automaticamente o tipo de guia e usa o modelo apropriado")
        print("\n📌 Modelos suportados:")
        print("   • Modelo geral (todos os tipos)")
        print("   • Modelos específicos por tipo (se treinados)")
        print("   • Modelo avançado de consulta (se disponível)")
        print("\n📌 Exemplo:")
        print("   python predizer_inteligente.py guias_novembro.csv")