from src import db
from src.models import Agente, AgenteTreino, Chat, Message 
from flask_login import current_user
from sqlalchemy import func
from datetime import datetime
import os
import json 
from werkzeug.utils import secure_filename
from flask import current_app

ALLOWED_EXTENSIONS_SERVICE = {'txt', 'pdf', 'csv', 'md', 'json', 'xlsx'}

def _allowed_file_service(filename):
    return '.' in filename and filename.rsplit('.', 1)[1].lower() in ALLOWED_EXTENSIONS_SERVICE

class AgentService:
    @staticmethod
    def create_agent_with_training_files(agent_data, files_list):
        """
        Cria um novo agente com seus dados e salva os arquivos de treino.
        agent_data: Dicionário com os dados do agente (nome, descricao, model_identifier, etc.)
        files_list: Lista de objetos de arquivo de request.files.getlist('arquivos')
        """
        print(f"[DEBUG SERVICE] Início create_agent_with_training_files")
        print(f"[DEBUG SERVICE] agent_data recebido: {agent_data}")
        print(f"[DEBUG SERVICE] files_list recebido (tipo): {type(files_list)}, (quantidade): {len(files_list) if isinstance(files_list, list) else 'N/A'}")
        if isinstance(files_list, list):
            for i, f in enumerate(files_list):
                print(f"[DEBUG SERVICE] Arquivo {i}: Nome={getattr(f, 'filename', 'N/A')}, Tipo={getattr(f, 'content_type', 'N/A')}, Tamanho={getattr(f, 'content_length', 'N/A')}")

        try:
            novo_agente = Agente(
                user_id=agent_data.get('user_id'),
                nome=agent_data.get('nome'),
                descricao=agent_data.get('descricao'),
                model_identifier=agent_data.get('model_identifier'),
                system_prompt=agent_data.get('system_prompt'),
                example_prompt=agent_data.get('examples_json'),
                welcome_message=agent_data.get('welcome_message'),
                temperature=agent_data.get('temperature'),
                max_tokens=agent_data.get('max_tokens')
            )
            
            try:
                if hasattr(Agente, 'top_p'):
                    novo_agente.top_p = agent_data.get('top_p')
                if hasattr(Agente, 'frequency_penalty'):
                    novo_agente.frequency_penalty = agent_data.get('frequency_penalty')
            except Exception as e:
                print(f"[DEBUG SERVICE] Aviso: Campos novos não disponíveis no banco: {str(e)}")
            
            db.session.add(novo_agente)
            db.session.flush() 
            print(f"[DEBUG SERVICE] Novo agente criado e flushado com ID: {novo_agente.id}")

            upload_folder_base = current_app.config.get('UPLOAD_FOLDER', 'uploads/agentes') 
            agent_specific_upload_folder = os.path.join(upload_folder_base, str(novo_agente.id))
            print(f"[DEBUG SERVICE] Verificando/Criando pasta de upload: {agent_specific_upload_folder}")
            os.makedirs(agent_specific_upload_folder, exist_ok=True)
            print(f"[DEBUG SERVICE] Pasta de upload verificada/criada.")

            print(f"[DEBUG SERVICE] Iniciando iteração sobre files_list ({len(files_list) if isinstance(files_list, list) else 'N/A'} arquivos).")
            
            if isinstance(files_list, list):
                for arquivo in files_list:
                    print(f"[DEBUG SERVICE] Processando arquivo: {getattr(arquivo, 'filename', 'N/A')}")
                    if arquivo and arquivo.filename and _allowed_file_service(arquivo.filename):
                        filename = secure_filename(arquivo.filename)
                        caminho_completo = os.path.join(agent_specific_upload_folder, filename)
                        print(f"[DEBUG SERVICE] Salvando arquivo: {filename} em {caminho_completo}")
                        arquivo.save(caminho_completo)
                        print(f"[DEBUG SERVICE] Arquivo {filename} salvo com sucesso.")
                        
                        novo_treino = AgenteTreino(
                            agente_id=novo_agente.id,
                            arquivo=filename 
                        )
                        db.session.add(novo_treino)
                        print(f"[DEBUG SERVICE] AgenteTreino para {filename} adicionado à sessão.")
                    else:
                         print(f"[DEBUG SERVICE] Arquivo inválido ou não permitido: {getattr(arquivo, 'filename', 'N/A')}")
            else:
                print(f"[DEBUG SERVICE] files_list não é uma lista ou está vazia de forma inesperada.")

            print(f"[DEBUG SERVICE] Tentando commit no banco de dados.")
            db.session.commit()
            print(f"[DEBUG SERVICE] Commit realizado com sucesso.")

            print(f"[DEBUG SERVICE] Fim create_agent_with_training_files (Sucesso).")
            return novo_agente, None
        except Exception as e:
            db.session.rollback()
            error_message = f"Erro no AgentService ao criar agente: {str(e)}"
            print(f"[DEBUG SERVICE] {error_message}")
            return None, error_message

    @staticmethod
    def get_user_agents_with_stats():
        try:
            if hasattr(current_user, 'role') and current_user.role == 'superadmin':
                user_agents = db.session.query(Agente).order_by(Agente.nome).all()
            else:
                user_agents = db.session.query(Agente).filter(Agente.user_id == current_user.id).order_by(Agente.nome).all()
            
            agents_list_with_stats = []
            for agent in user_agents:
                conversation_count = db.session.query(func.count(Chat.id))\
                    .filter(Chat.agent_id == agent.id, Chat.user_id == current_user.id)\
                    .scalar() or 0

                message_count = db.session.query(func.count(Message.id))\
                    .join(Chat, Chat.id == Message.chat_id)\
                    .filter(Chat.agent_id == agent.id, Chat.user_id == current_user.id)\
                    .scalar() or 0
                
                tokens_used = "N/A" 

                initials = "".join([word[0] for word in agent.nome.split()[:2]]).upper() if agent.nome else "AG"
                
                model_display = agent.model_identifier if hasattr(agent, 'model_identifier') and agent.model_identifier else "Não Definido"
                
                description_text = agent.descricao if agent.descricao else "Sem descrição."

                creator_username = agent.user.username if hasattr(agent, 'user') and agent.user and hasattr(agent.user, 'username') else "-"
            
                agent_dict = {
                    "id": agent.id,
                    "name": agent.nome or "Agente Sem Nome",
                    "initials": initials,
                    "model": model_display,
                    "description": description_text,
                    "creator_username": creator_username,
                    "public_token": agent.public_token,
                    "stats": {
                        "conversations": conversation_count,
                        "messages": message_count,
                        "tokens": tokens_used 
                    }
                }
                agents_list_with_stats.append(agent_dict)
            
            return agents_list_with_stats, None
        except Exception as e:
            print(f"Erro em AgentService.get_user_agents_with_stats: {str(e)}")
            return [], str(e)

    @staticmethod
    def delete_agent(agent_id):
        try:
            agente = db.session.query(Agente).filter_by(id=agent_id, user_id=current_user.id).first()
            if agente:
                db.session.delete(agente)
                db.session.commit()
                return True, None
            return False, "Agente não encontrado ou acesso negado."
        except Exception as e:
            db.session.rollback()
            print(f"Erro ao excluir agente {agent_id}: {str(e)}")
            return False, str(e)

    @staticmethod
    def get_user_agents():
        return Agente.query.filter_by(user_id=current_user.id).all()

    @staticmethod
    def get_agent(agent_id):
        return Agente.query.filter_by(id=agent_id, user_id=current_user.id).first()

    @staticmethod
    def delete_agent(agent_id):
        try:
            agente = Agente.query.filter_by(id=agent_id, user_id=current_user.id).first()
            if agente:
                for treino in agente.treinos:
                    file_path = os.path.join('uploads', treino.arquivo)
                    if os.path.exists(file_path):
                        os.remove(file_path)
                
                db.session.delete(agente)
                db.session.commit()
                return True, None
            return False, "Agente não encontrado"
        except Exception as e:
            db.session.rollback()
            return False, str(e) 
        
    @staticmethod
    def get_agent_by_id(agent_id):
        try:
            agent = db.session.query(Agente).filter_by(id=agent_id, user_id=current_user.id).first()
            if not agent:
                return None, "Agente não encontrado ou acesso negado."
            return agent, None
        except Exception as e:
            print(f"Erro em AgentService.get_agent_by_id: {str(e)}")
            return None, str(e)

    @staticmethod
    def get_training_files_content(agent_id):
        """
        Recupera e lê o conteúdo dos arquivos de treino para um dado agente.
        Retorna uma lista de tuplas (filename, content).
        """
        print(f"[DEBUG SERVICE] Iniciando get_training_files_content para agente_id: {agent_id}")
        training_files_content = []
        try:
            treinos = db.session.query(AgenteTreino).filter_by(agente_id=agent_id).all()
            print(f"[DEBUG SERVICE] Encontrados {len(treinos)} registros de treino.")

            if not treinos:
                print("[DEBUG SERVICE] Nenhum arquivo de treino encontrado para este agente.")
                return [], None

            upload_folder_base = current_app.config.get('UPLOAD_FOLDER', 'uploads/agentes')
            
            for treino in treinos:
                filename = treino.arquivo
                agent_specific_upload_folder = os.path.join(upload_folder_base, str(agent_id))
                file_path = os.path.join(agent_specific_upload_folder, filename)
                print(f"[DEBUG SERVICE] Tentando ler arquivo: {file_path}")

                if os.path.exists(file_path):
                    try:
                        with open(file_path, 'r', encoding='utf-8') as f:
                            content = f.read()
                        print(f"[DEBUG SERVICE] Arquivo {filename} lido com sucesso. Tamanho: {len(content)} bytes")
                        training_files_content.append((filename, content))
                    except Exception as file_read_error:
                        print(f"[DEBUG SERVICE] Erro ao ler arquivo {filename}: {str(file_read_error)}")
                        pass
                else:
                    print(f"[DEBUG SERVICE] Arquivo não encontrado no caminho: {file_path}")

            print(f"[DEBUG SERVICE] Fim get_training_files_content (Sucesso). Total de arquivos lidos: {len(training_files_content)}")
            return training_files_content, None

        except Exception as e:
            error_message = f"Erro no AgentService ao obter conteúdo dos arquivos de treino: {str(e)}"
            print(f"[DEBUG SERVICE] {error_message}")
            return None, error_message