import tkinter as tk
from tkinter import messagebox, filedialog, ttk
import threading
import asyncio
import os
import time
import json
import logging
import math
import sys
from datetime import datetime
from ccc import HappyCheck, Account

# Import our custom license manager
try:
    import license_manager
except ImportError:
    license_manager = None

def resource_path(relative_path):
    """ Get absolute path to resource, works for dev and for PyInstaller """
    try:
        # PyInstaller creates a temp folder and stores path in _MEIPASS
        base_path = sys._MEIPASS
    except Exception:
        base_path = os.path.abspath(".")
    return os.path.join(base_path, relative_path)

# --- PALETA GORE / EL CIEN BRAZOS (BIO-HACKER) ---
BLOOD_RED = "#8B0000"
BONE_WHITE = "#E5E4E2"
DIRTY_FLESH = "#3B2F2F"
DARK_VOID = "#050505"
TOXIC_GREEN = "#39FF14"
CYBER_NERVE = "#FF00FF"
WARNING_ORANGE = "#FF4500"

STENCIL_FONT = ("Courier", 20, "bold")
STENCIL_SMALL = ("Courier", 11, "bold")
TECH_FONT = ("Consolas", 10)
SYSTEM_FONT = ("Courier", 9, "bold")

class CienBrazosGUI:
    def __init__(self, root):
        self.root = root
        self.root.title("EL CIEN BRAZOS v2.0 - BIO-MECHANICAL SCANNER")
        self.root.geometry("680x850")
        self.root.configure(bg=DARK_VOID)
        
        # State
        self.running = False
        self.paused = False
        self.valid_results = []
        self.checker = None
        self.accounts_file = None
        self.viz_angle = 0
        
        # Checking license status
        self.is_licensed = False
        if license_manager:
            self.is_licensed = license_manager.is_activated()
        else:
            # Fallback safe behavior if manager is missing
            self.is_licensed = True

        if not self.is_licensed:
            self.build_activation_ui()
        else:
            self.build_main_ui()

    def build_activation_ui(self):
        # Header Box
        self.header = tk.Frame(self.root, bg=BLOOD_RED, height=140, bd=3, relief="flat")
        self.header.pack(fill="x", side="top", padx=5, pady=5)
        self.header.pack_propagate(False)
        
        tk.Label(self.header, text="[ SYSTEM ENFORCEMENT ]", 
                 font=STENCIL_FONT, fg=BONE_WHITE, bg=BLOOD_RED).pack(pady=(20, 5))
        tk.Label(self.header, text="CORE ENGINES LOCKED - LICENSE VERIFICATION REQUIRED", 
                 font=SYSTEM_FONT, fg=BONE_WHITE, bg=BLOOD_RED).pack()

        # Activation frame
        self.act_frame = tk.LabelFrame(self.root, text=" BIO-ENCRYPTION KEY ACTIVATION ", 
                                       bg=DARK_VOID, fg=BLOOD_RED, font=STENCIL_SMALL, bd=1, padx=20, pady=20)
        self.act_frame.pack(fill="both", expand=True, padx=25, pady=25)

        tk.Label(self.act_frame, text="🔒 CORE SHUTDOWN ACTIVE", font=("Courier", 16, "bold"), fg=BLOOD_RED, bg=DARK_VOID).pack(pady=(10, 20))

        # HWID Label
        tk.Label(self.act_frame, text="YOUR SYSTEM HWID (MACHINE ID):", font=SYSTEM_FONT, fg=BONE_WHITE, bg=DARK_VOID).pack(anchor="w", pady=(0, 5))
        
        hwid = license_manager.get_machine_id() if license_manager else "UNKNOWN_HWID"
        self.hwid_entry = tk.Entry(self.act_frame, bg="#110000", fg=TOXIC_GREEN, font=TECH_FONT, bd=1)
        self.hwid_entry.insert(0, hwid)
        self.hwid_entry.config(state="readonly")
        self.hwid_entry.pack(fill="x", pady=(0, 10))

        def copy_hwid():
            self.root.clipboard_clear()
            self.root.clipboard_append(hwid)
            messagebox.showinfo("Clipboard", "Machine ID copied to clipboard.")

        self.btn_copy_hwid = tk.Button(self.act_frame, text="[ COPY MACHINE ID ]", font=SYSTEM_FONT,
                                       bg=DIRTY_FLESH, fg=BONE_WHITE, activebackground=BLOOD_RED, activeforeground=BONE_WHITE,
                                       bd=1, relief="flat", command=copy_hwid)
        self.btn_copy_hwid.pack(pady=(0, 25))

        # License input
        tk.Label(self.act_frame, text="ENTER ACTIVATION LICENSE KEY:", font=SYSTEM_FONT, fg=BONE_WHITE, bg=DARK_VOID).pack(anchor="w", pady=(0, 5))
        self.key_entry = tk.Entry(self.act_frame, bg="#110000", fg=TOXIC_GREEN, font=TECH_FONT, bd=1)
        self.key_entry.pack(fill="x", pady=(0, 20))

        def attempt_activation():
            key = self.key_entry.get().strip()
            if not key:
                messagebox.showerror("Activation Fail", "Nerve interface detected no code injection.")
                return
            if license_manager and license_manager.save_license(key):
                messagebox.showinfo("Neural Link", "Nerve systems accepted. Biomechanical modules unlocked.")
                for widget in self.root.winfo_children():
                    widget.destroy()
                self.build_main_ui()
            else:
                messagebox.showerror("Necrosis", "Code signature verification failed. Target HWID mismatch.")

        self.btn_inject = tk.Button(self.act_frame, text="[ INJECT SYNERGY CODE ]", font=STENCIL_SMALL,
                                    bg=BLOOD_RED, fg=BONE_WHITE, activebackground=TOXIC_GREEN, activeforeground=DARK_VOID,
                                    bd=1, relief="flat", height=2, command=attempt_activation)
        self.btn_inject.pack(fill="x", pady=(10, 0))

    def build_main_ui(self):
        self.create_widgets()
        self.animate_viz()
        self.log_system("NEURAL LINKS READY. AWAITING INFECTED INTEL.")

    def create_widgets(self):
        # --- HEADER (THE BRAIN) ---
        self.header = tk.Frame(self.root, bg=BLOOD_RED, height=140, bd=3, relief="flat")
        self.header.pack(fill="x", side="top", padx=5, pady=5)
        self.header.pack_propagate(False)
        
        # Bio-Signal Canvas
        self.viz_canvas = tk.Canvas(self.header, bg=DARK_VOID, height=50, highlightthickness=1, highlightbackground=BONE_WHITE)
        self.viz_canvas.pack(fill="x", padx=40, pady=(15, 0))
        self.viz_line = self.viz_canvas.create_line(0, 25, 600, 25, fill=TOXIC_GREEN, width=2)
        
        tk.Label(self.header, text="[ EL CIEN BRAZOS ]", 
                 font=STENCIL_FONT, fg=BONE_WHITE, bg=BLOOD_RED).pack()
        tk.Label(self.header, text="MULTI-ARMED DATA EXTRACTION SYSTEM - @LACASADELTRUCO", 
                 font=SYSTEM_FONT, fg=BONE_WHITE, bg=BLOOD_RED).pack()
        
        # --- PULSE MONITOR (STATS) ---
        self.radar_frame = tk.Frame(self.root, bg=DARK_VOID)
        self.radar_frame.pack(fill="x", padx=15, pady=5)
        
        self.stat_total = self.create_nerve_box(self.radar_frame, "CELLS", "0", "#221111")
        self.stat_valid = self.create_nerve_box(self.radar_frame, "SYNERGY", "0", BLOOD_RED)
        self.stat_failed = self.create_nerve_box(self.radar_frame, "NECROSIS", "0", "#330000")
        self.stat_speed = self.create_nerve_box(self.radar_frame, "RPM", "0.0", "#111111")

        # --- NERVE RACK (CONFIG) ---
        self.rack = tk.LabelFrame(self.root, text=" NEURAL PARAMETERS ", 
                                 bg=DARK_VOID, fg=TOXIC_GREEN, font=STENCIL_SMALL, bd=1, padx=10, pady=5)
        self.rack.pack(fill="x", padx=15, pady=5)
        
        # Targets
        tk.Label(self.rack, text="INJECT TO:", font=SYSTEM_FONT, fg=BONE_WHITE, bg=DARK_VOID).grid(row=0, column=0, sticky="w")
        self.test_entry = tk.Entry(self.rack, bg="#110000", fg=TOXIC_GREEN, font=TECH_FONT, bd=1, width=40)
        self.test_entry.grid(row=0, column=1, padx=10, pady=5, sticky="ew")
        self.test_entry.insert(0, "test1@mail.com")
        
        # Threads
        sub = tk.Frame(self.rack, bg=DARK_VOID)
        sub.grid(row=1, column=1, sticky="w")
        tk.Label(sub, text="ARMS:", font=SYSTEM_FONT, fg=BONE_WHITE, bg=DARK_VOID).pack(side="left")
        self.threads_entry = tk.Entry(sub, bg="#110000", fg=TOXIC_GREEN, font=TECH_FONT, bd=1, width=10)
        self.threads_entry.pack(side="left", padx=5)
        self.threads_entry.insert(0, "100") # Cien brazos = 100 threads default
        
        # Msg
        tk.Label(self.rack, text="PAYLOAD:", font=SYSTEM_FONT, fg=BONE_WHITE, bg=DARK_VOID).grid(row=2, column=0, sticky="nw")
        self.msg_text = tk.Text(self.rack, bg="#0A0000", fg=BONE_WHITE, font=TECH_FONT, bd=1, height=3)
        self.msg_text.grid(row=2, column=1, padx=10, pady=5, sticky="ew")
        self.msg_text.insert("1.0", "Infeccion exitosa.\n@lacasadeltruco")
        
        self.rack.columnconfigure(1, weight=1)

        # --- SURGICAL CONTROLS (THE TRIGGER) ---
        self.trigger_frame = tk.Frame(self.root, bg=DARK_VOID)
        self.trigger_frame.pack(fill="x", padx=15, pady=5)
        
        btn_s = {"font": SYSTEM_FONT, "bd": 1, "relief": "solid", "padx": 10, "pady": 8}
        
        self.btn_start = tk.Button(self.trigger_frame, text="[ INYECTAR ]", 
                                   bg=BLOOD_RED, fg=BONE_WHITE, command=self.start_mission, **btn_s)
        self.btn_start.pack(side="left", padx=2, fill="x", expand=True)
        
        self.btn_pause = tk.Button(self.trigger_frame, text="[ PAUSAR ]", 
                                   bg="#333333", fg=BONE_WHITE, command=self.toggle_pause, state="disabled", **btn_s)
        self.btn_pause.pack(side="left", padx=2, fill="x", expand=True)
        
        self.btn_stop = tk.Button(self.trigger_frame, text="[ DETENER ]", 
                                  bg="#660000", fg=BONE_WHITE, command=self.stop_mission, state="disabled", **btn_s)
        self.btn_stop.pack(side="left", padx=2, fill="x", expand=True)
        
        self.btn_clear = tk.Button(self.trigger_frame, text="[ LIMPIAR ]", 
                                   bg="#000000", fg=WARNING_ORANGE, command=self.clear_system, **btn_s)
        self.btn_clear.pack(side="left", padx=2, fill="x", expand=True)

        # --- THE SPITTER (EXTRACTION AREA) ---
        self.spitter = tk.Frame(self.root, bg="#0A0000", bd=1, relief="solid")
        self.spitter.pack(fill="both", expand=True, padx=15, pady=5)
        
        self.inf_label = tk.Label(self.spitter, text=">>> [ CLICK PARA CARGAR MUESTRA .TXT ] <<<", 
                                  font=SYSTEM_FONT, fg=BLOOD_RED, bg="#0A0000", cursor="hand2")
        self.inf_label.pack(fill="x", pady=2)
        self.inf_label.bind("<Button-1>", lambda e: self.load_file())
        
        self.results_text = tk.Text(self.spitter, bg="#000000", fg=TOXIC_GREEN, 
                                   font=TECH_FONT, borderwidth=0, highlightthickness=0, state="disabled")
        self.results_text.pack(fill="both", expand=True, side="left", padx=5, pady=5)
        
        self.sb = tk.Scrollbar(self.spitter, command=self.results_text.yview)
        self.sb.pack(side="right", fill="y")
        self.results_text.config(yscrollcommand=self.sb.set)

        self.comms = tk.Label(self.root, text="STATUS: STANDBY", font=SYSTEM_FONT, fg=WARNING_ORANGE, bg="#050505", anchor="w", padx=20)
        self.comms.pack(fill="x")

        # --- EXTRACTION BLOCK ---
        self.ext_frame = tk.Frame(self.root, bg=DARK_VOID)
        self.ext_frame.pack(fill="x", padx=15, pady=(5, 15))

        self.btn_copy = tk.Button(self.ext_frame, text="[ COPIAR VÁLIDAS ]", 
                                 bg=DIRTY_FLESH, fg=BONE_WHITE, command=self.copy_to_clipboard, font=STENCIL_SMALL, bd=1, relief="solid", pady=10)
        self.btn_copy.pack(side="left", fill="x", expand=True, padx=(0, 2))

        self.btn_export = tk.Button(self.ext_frame, text="[ EXTRAER .TXT ]", 
                                   bg=BLOOD_RED, fg=BONE_WHITE, command=self.export_intel, font=STENCIL_SMALL, bd=1, relief="solid", pady=10)
        self.btn_export.pack(side="left", fill="x", expand=True, padx=(2, 0))

    def create_nerve_box(self, parent, title, value, color):
        box = tk.Frame(parent, bg=color, bd=1, relief="flat", height=50)
        box.pack(side="left", padx=2, fill="both", expand=True)
        box.pack_propagate(False)
        tk.Label(box, text=title, font=SYSTEM_FONT, fg=BONE_WHITE, bg=color).pack()
        lbl = tk.Label(box, text=value, font=STENCIL_SMALL, fg=BONE_WHITE, bg=color)
        lbl.pack()
        return lbl

    def animate_viz(self):
        width = 600
        points = []
        amp = 20 if self.running and not self.paused else 3
        freq = 0.2 if self.running and not self.paused else 0.05
        for x in range(0, width, 5):
            y = 25 + amp * math.sin(freq * (x + self.viz_angle))
            if self.running and not self.paused: y += (time.time()*100 % 10 - 5)
            points.extend([x, y])
        self.viz_canvas.coords(self.viz_line, *points)
        self.viz_angle += 10 if self.running and not self.paused else 2
        self.root.after(40, self.animate_viz)

    def log_system(self, msg):
        self.comms.config(text=f"INFO > {msg}")

    def log_result(self, text, type="INFO"):
        self.results_text.config(state="normal")
        timestamp = datetime.now().strftime('%H:%M:%S')
        self.results_text.insert("end", f"{timestamp} | ", "time")
        self.results_text.insert("end", f"{text}\n", type)
        
        self.results_text.tag_config("time", foreground="#555555")
        self.results_text.tag_config("INFO", foreground=TOXIC_GREEN)
        self.results_text.tag_config("SYNERGY", foreground=TOXIC_GREEN, font=TECH_FONT)
        self.results_text.tag_config("TEST", foreground=CYBER_NERVE)
        self.results_text.tag_config("FAIL", foreground=BLOOD_RED)
        
        self.results_text.see("end")
        self.results_text.config(state="disabled")

    def load_file(self):
        path = filedialog.askopenfilename(filetypes=[("Text files", "*.txt")])
        if path:
            self.accounts_file = path
            self.log_system(f"CELLS LOADED: {os.path.basename(path)}")
            try:
                dum = HappyCheck()
                accs = dum.load_accounts(path)
                self.stat_total.config(text=str(len(accs)))
                self.inf_label.config(text=f"SAMPLE: {os.path.basename(path)} [{len(accs)}]", fg=TOXIC_GREEN)
            except Exception as e:
                messagebox.showerror("IO_ERR", str(e))

    def on_check_callback(self, account, stats):
        self.root.after(0, self.update_ui, account, stats)

    def update_ui(self, acc, stats):
        self.stat_valid.config(text=str(stats['valid']))
        self.stat_failed.config(text=str(stats['auth_failed'] + stats['invalid']))
        el = time.time() - stats['start_time']
        rate = stats['checked'] / max(el, 1)
        self.stat_speed.config(text=f"{rate:.1f}")
        
        if acc.status == 'valid':
            info = acc.raw_data if acc.raw_data else f"{acc.email}:{acc.password}"
            self.valid_results.append(info)
            
            self.results_text.config(state="normal")
            self.results_text.insert("end", f"{info}\n", "SYNERGY")
            self.results_text.tag_config("SYNERGY", foreground=TOXIC_GREEN)
            self.results_text.see("end")
            self.results_text.config(state="disabled")

            if acc.test_sent:
                self.log_system(f"MISSION SUCCESS: {acc.email[:25]} INJECTED.")
            elif self.checker and self.checker.test_emails:
                self.log_system(f"SYNERGY OK | TEST FAIL: {acc.email[:25]}")
            else:
                self.log_system(f"DETECTED: {acc.email[:25]}")
        else:
            self.log_system(f"TRACE: {acc.email[:30]}")

    def start_mission(self):
        if not self.accounts_file:
            messagebox.showwarning("ERR", "NO SAMPLE LOADED.")
            return
        self.running = True
        self.paused = False
        self.btn_start.config(state="disabled")
        self.btn_pause.config(state="normal", text="[ PAUSAR ]", bg="#333333")
        self.btn_stop.config(state="normal")
        self.btn_clear.config(state="disabled")
        self.log_system("INFECTION TRIGGERED. PUMPING CELLS...")
        threading.Thread(target=self.run_checker, daemon=True).start()

    def run_checker(self):
        try:
            loop = asyncio.new_event_loop()
            asyncio.set_event_loop(loop)
            test_emails = [e.strip() for e in self.test_entry.get().replace(';', ',').split(',') if '@' in e]
            try: th = int(self.threads_entry.get())
            except: th = 100
            msg = self.msg_text.get("1.0", "end-1c").strip()
            self.checker = HappyCheck(test_emails=test_emails, on_account_checked=self.on_check_callback, custom_msg=msg)
            self.checker.config['max_concurrent'] = th
            accs = self.checker.load_accounts(self.accounts_file)
            loop.run_until_complete(self.checker.process_batch(accs, mode="auto"))
            loop.close()
        except Exception as e:
            self.root.after(0, lambda: messagebox.showerror("CRIT", str(e)))
        self.root.after(0, self.mission_complete)

    def mission_complete(self):
        self.running = False
        self.btn_start.config(state="normal")
        self.btn_pause.config(state="disabled", text="[ PAUSAR ]")
        self.btn_stop.config(state="disabled")
        self.btn_clear.config(state="normal")
        self.log_system("INFECTION CYCLE COMPLETE.")
        messagebox.showinfo("INFO", f"EXTRACTED {len(self.valid_results)} UNITS.")

    def toggle_pause(self):
        if not self.checker: return
        if self.paused:
            self.checker.resume(); self.paused = False
            self.btn_pause.config(text="[ PAUSAR ]", bg="#333333")
            self.log_system("RESUMING PUMP.")
        else:
            self.checker.pause(); self.paused = True
            self.btn_pause.config(text="[ REANUDAR ]", bg=BLOOD_RED)
            self.log_system("PUMP PAUSED.")

    def stop_mission(self):
        if self.checker: self.checker.stop()
        self.running = False; self.paused = False
        self.log_system("PUMP ABORTED.")
        self.btn_stop.config(state="disabled")
        self.btn_start.config(state="normal")

    def clear_system(self):
        if messagebox.askyesno("WIPE", "PURGE NEURAL CACHE?"):
            self.results_text.config(state="normal")
            self.results_text.delete("1.0", "end")
            self.results_text.config(state="disabled")
            self.valid_results = []
            self.accounts_file = None
            self.stat_valid.config(text="0"); self.stat_failed.config(text="0"); self.stat_speed.config(text="0.0")
            self.stat_total.config(text="0")
            self.inf_label.config(text=">>> [ CLICK PARA CARGAR MUESTRA .TXT ] <<<", fg=BLOOD_RED)
            self.log_system("CACHE PURGED. NEURAL PATHS RESET.")

    def export_intel(self):
        if not self.valid_results: 
            self.log_system("ERR: NO INTEL TO EXTRACT.")
            return
        p = filedialog.asksaveasfilename(defaultextension=".txt", initialfile="Intel_Extraida.txt")
        if p:
            with open(p, "w") as f: f.write("\n".join(self.valid_results))
            messagebox.showinfo("OK", "DATA DUMPED.")
            self.log_system("INTEL EXPORTED TO DISK.")

    def copy_to_clipboard(self):
        if not self.valid_results:
            self.log_system("ERR: NOTHING TO COPY.")
            return
        self.root.clipboard_clear()
        self.root.clipboard_append("\n".join(self.valid_results))
        self.log_system("COPIED TO CLIPBOARD. READY TO INJECT.")
        messagebox.showinfo("SYNERGY", f"{len(self.valid_results)} cuentas copiadas al portapapeles.")

if __name__ == "__main__":
    root = tk.Tk()
    app = CienBrazosGUI(root)
    root.mainloop()
