import os
import json
import redis
import subprocess
import base64
import random
import urllib.request
import urllib.error
import time

class SwarmAgent:
    def __init__(self, task_data):
        self.data = task_data
        self.repo_name = task_data.get('repository')
        self.repo_url = f"http://10.99.0.3:3000/{self.repo_name}.git"
        self.local_path = os.path.join("/home/deploy/projetos", self.repo_name.split('/')[-1])
        
        # Conexão Redis para pegar chaves do pool
        self.r = redis.Redis(host='10.99.0.3', port=6379, password='clube67_dragonfly_pass_9903', db=0, decode_responses=True)

    def get_api_key(self, provider):
        pool = json.loads(self.r.get('swarm:keys:pool'))
        active_keys = [k['key'] for k in pool.get(provider, []) if k.get('status') == 'active']
        if not active_keys:
            raise Exception(f"Nenhuma chave ativa encontrada para o provedor: {provider}")
        return random.choice(active_keys)

    def setup_workspace(self):
        os.makedirs("/home/deploy/projetos", exist_ok=True)
        if not os.path.exists(self.local_path):
            print(f" [>] Clonando repositório {self.repo_url} em {self.local_path}...")
            subprocess.run(["git", "clone", self.repo_url, self.local_path])
        else:
            print(f" [>] Atualizando repositório em {self.local_path}...")
            subprocess.run(["git", "-C", self.local_path, "pull"])

    def run_command(self, command):
        """Executa comandos shell na VPS 4"""
        print(f" [Exec] Rodando comando: {command}")
        result = subprocess.run(command, shell=True, capture_output=True, text=True, cwd=self.local_path)
        return {"stdout": result.stdout, "stderr": result.stderr}

    def write_file(self, path, content):
        """Escreve/Edita arquivos no projeto"""
        print(f" [Exec] Escrevendo arquivo: {path}")
        full_path = os.path.join(self.local_path, path)
        os.makedirs(os.path.dirname(full_path), exist_ok=True)
        with open(full_path, "w") as f:
            f.write(content)
        return f"Arquivo {path} escrito com sucesso."

    def read_file(self, path):
        """Lê arquivos do projeto"""
        print(f" [Exec] Lendo arquivo: {path}")
        full_path = os.path.join(self.local_path, path)
        if os.path.exists(full_path):
            with open(full_path, "r") as f:
                return f.read()
        return f"Erro: Arquivo {path} não encontrado."

    def post_comment(self, message):
        """Posta um comentário de feedback na Issue do Gitea"""
        issue_id = self.data.get('data', {}).get('issue', {}).get('number')
        if not issue_id: 
            return
        url = f"http://10.99.0.3:3000/api/v1/repos/{self.repo_name}/issues/{issue_id}/comments"
        
        # Auth Basic
        auth_str = 'ruicesar:h$tg@g5aga$ra1E3$C-yHW$-BA@DF2@Grfa!3#'
        base64_auth = base64.b64encode(auth_str.encode('ascii')).decode('ascii')
        
        data = json.dumps({"body": message}).encode('utf-8')
        req = urllib.request.Request(url, data=data, method='POST')
        req.add_header('Content-Type', 'application/json')
        req.add_header('Authorization', f'Basic {base64_auth}')
        
        try:
            with urllib.request.urlopen(req) as response:
                if response.status == 201:
                    print(f" [✓] Comentário postado na Issue #{issue_id}")
        except Exception as e:
            print(f" [E] Falha ao postar comentário no Gitea: {e}")

    def call_openai(self, messages, system_instruction, api_key):
        """Chama a API do OpenAI com ferramentas em formato puramente nativo"""
        url = 'https://api.openai.com/v1/chat/completions'
        headers = {
            'Authorization': f'Bearer {api_key}',
            'Content-Type': 'application/json'
        }
        
        # OpenAI estruturado com o systemInstruction no topo do array
        payload_messages = [{"role": "system", "content": system_instruction}] + messages
        
        tools = [
            {
                "type": "function",
                "function": {
                    "name": "read_file",
                    "description": "Lê o conteúdo de um arquivo do projeto para análise técnica.",
                    "parameters": {
                        "type": "object",
                        "properties": {
                            "path": {"type": "string", "description": "Caminho relativo do arquivo no repositório."}
                        },
                        "required": ["path"]
                    }
                }
            },
            {
                "type": "function",
                "function": {
                    "name": "write_file",
                    "description": "Cria ou edita um arquivo com o novo conteúdo fornecido.",
                    "parameters": {
                        "type": "object",
                        "properties": {
                            "path": {"type": "string", "description": "Caminho relativo do arquivo no repositório."},
                            "content": {"type": "string", "description": "Conteúdo completo a ser gravado no arquivo."}
                        },
                        "required": ["path", "content"]
                    }
                }
            },
            {
                "type": "function",
                "function": {
                    "name": "run_command",
                    "description": "Executa um comando de terminal (como NPM, Docker, Git, etc) no diretório do projeto.",
                    "parameters": {
                        "type": "object",
                        "properties": {
                            "command": {"type": "string", "description": "Comando shell a ser executado."}
                        },
                        "required": ["command"]
                    }
                }
            }
        ]
        
        payload = {
            "model": "gpt-4o-mini",
            "messages": payload_messages,
            "tools": tools,
            "tool_choice": "auto"
        }
        
        req = urllib.request.Request(url, data=json.dumps(payload).encode('utf-8'), headers=headers, method='POST')
        with urllib.request.urlopen(req) as res:
            return json.loads(res.read().decode('utf-8'))

    def execute(self):
        self.setup_workspace()
        
        # Identificação de Localização Automática via .vps_identity
        identity_path = "/home/deploy/.vps_identity"
        vps_name = "VPS-DESCONHECIDA"
        vps_ip = "127.0.0.1"
        vps_role = "Desconhecido"
        danger_level = "Desconhecido"
        
        if os.path.exists(identity_path):
            try:
                with open(identity_path, "r") as f:
                    identity = json.load(f)
                    vps_name = identity.get("vps_name", vps_name)
                    vps_ip = identity.get("ip_vpn", vps_ip)
                    vps_role = identity.get("role", vps_role)
                    danger_level = identity.get("danger_level", danger_level)
            except Exception as e_id:
                print(f" [!] Erro ao ler .vps_identity: {e_id}")
        else:
            # Fallback dinâmico caso o arquivo não exista
            ips = subprocess.getoutput("hostname -I").split()
            vps_ip = next((ip for ip in ips if ip.startswith("10.99.")), ips[0] if ips else "127.0.0.1")
            vps_name = subprocess.getoutput("hostname")
            
        # Carrega a Doutrina de Agentes de forma dinâmica e em tempo real do Gitea (VPS 3)
        doutrina = ""
        auth_str = 'ruicesar:h$tg@g5aga$ra1E3$C-yHW$-BA@DF2@Grfa!3#'
        base64_auth = base64.b64encode(auth_str.encode('ascii')).decode('ascii')
        url = "http://10.99.0.3:3000/api/v1/repos/ruicesar/instrucoes_gerais/contents/global/doutrina_agentes.md"
        
        req = urllib.request.Request(url, method='GET')
        req.add_header('Authorization', f'Basic {base64_auth}')
        
        try:
            with urllib.request.urlopen(req) as response:
                if response.status == 200:
                    res_data = json.loads(response.read().decode('utf-8'))
                    encoded_content = res_data.get('content', '')
                    # Gitea returns content in base64, usually with newlines
                    doutrina = base64.b64decode(encoded_content.replace('\n', '')).decode('utf-8')
                    print(" [✓] Doutrina carregada dinamicamente via API Gitea (JIT).")
        except Exception as e:
            print(f" [!] Falha ao carregar Doutrina via API Gitea, tentando ler do backup local... {e}")
            # Fallback seguro para o backup local caso o Gitea esteja fora do ar
            for fallback_path in ["/home/deploy/stack/instrucoes/global/doutrina_agentes.md", "/home/deploy/instrucoes/global/doutrina_agentes.md"]:
                if os.path.exists(fallback_path):
                    with open(fallback_path, "r") as f:
                        doutrina = f.read()
                        print(f" [✓] Doutrina carregada do backup local: {fallback_path}")
                        break
        
        # Consciência Situacional Injetada
        situational_awareness = (
            f"\n\n[CONSCIÊNCIA SITUACIONAL]:\n"
            f"- Servidor Atual: {vps_name}\n"
            f"- IP VPN Local: {vps_ip}\n"
            f"- Função da VPS: {vps_role}\n"
            f"- Nível de Perigo: {danger_level}\n"
        )
        system_instruction = doutrina + situational_awareness
        
        task = self.data.get('data', {}).get('issue', {}).get('body', 'Corrigir projeto')
        print(f" [!] Agente iniciando na {vps_name} ({vps_ip}) para resolver a tarefa.")
        
        # Histórico inicial
        messages = [
            {
                "role": "user",
                "content": f"Tarefa: {task}. Diretório do projeto: {self.local_path}. Analise o código e corrija a regressão aplicando as mudanças necessárias."
            }
        ]
        
        api_key = self.get_api_key('openai')
        feedback_steps = []
        final_text = ""
        
        # Loop de multi-turn de ferramentas (máximo 15 iterações)
        for turn in range(15):
            print(f" [>] Iniciando turno {turn + 1} com o cérebro OpenAI (GPT-4o-mini)...")
            try:
                response = self.call_openai(messages, system_instruction, api_key)
            except Exception as e:
                print(f" [E] Erro ao chamar a API do OpenAI: {e}")
                feedback_steps.append(f"* **Erro na API**: {e}")
                break
            
            choices = response.get('choices', [])
            if not choices:
                print(" [E] Nenhuma resposta retornada do OpenAI.")
                break
                
            assistant_message = choices[0].get('message', {})
            content = assistant_message.get('content')
            if content:
                final_text += content + "\n"
                
            # Mantém no histórico a resposta do modelo
            messages.append(assistant_message)
            
            tool_calls = assistant_message.get('tool_calls', [])
            if not tool_calls:
                print(" [🏁] Ciclo finalizado pelo modelo de IA.")
                break
                
            print(f" [!] OpenAI solicitou {len(tool_calls)} chamadas de ferramentas.")
            
            # Para o OpenAI, processamos cada chamada sequencialmente e adicionamos o resultado ao histórico
            for tool_call in tool_calls:
                func_name = tool_call.get('function', {}).get('name')
                func_args_str = tool_call.get('function', {}).get('arguments', '{}')
                try:
                    args = json.loads(func_args_str)
                except Exception as e_args:
                    args = {}
                    
                print(f" [!] Executando ferramenta: {func_name} (args: {args})")
                result_data = None
                try:
                    if func_name == "read_file":
                        path = args.get('path')
                        result_data = self.read_file(path)
                        feedback_steps.append(f"* **Lendo**: `{path}`")
                    elif func_name == "write_file":
                        path = args.get('path')
                        content_to_write = args.get('content')
                        result_data = self.write_file(path, content_to_write)
                        feedback_steps.append(f"* **Escrevendo**: `{path}`")
                    elif func_name == "run_command":
                        cmd = args.get('command')
                        result_data = self.run_command(cmd)
                        feedback_steps.append(f"* **Rodando**: `{cmd}`")
                except Exception as e_func:
                    print(f" [E] Erro ao rodar ferramenta {func_name}: {e_func}")
                    result_data = f"Erro de execução da ferramenta: {e_func}"
                
                # Prepara o feedback do tool e anexa ao histórico
                messages.append({
                    "role": "tool",
                    "tool_call_id": tool_call.get('id'),
                    "name": func_name,
                    "content": json.dumps(result_data) if isinstance(result_data, dict) else str(result_data)
                })
                
        # Formata o feedback e posta de volta no Gitea
        steps_str = "\n".join(feedback_steps)
        final_comment = (
            f"### 🤖 [VPS 4 - EXECUTOR SWARM GPT-4o-mini]:\n\n"
            f"{final_text}\n\n"
            f"**⚙️ Ações e Diagnóstico de Infraestrutura:**\n{steps_str}"
        )
        self.post_comment(final_comment)

if __name__ == "__main__":
    import argparse
    parser = argparse.ArgumentParser()
    parser.add_argument("--data")
    args = parser.parse_args()
    if args.data:
        SwarmAgent(json.loads(args.data)).execute()
