# ==============================================================================
# MenV4 RC - Client Agent PC (Windows, macOS, Linux)
# ==============================================================================
# Rulat pe calculatorul care urmează să fie controlat la distanță.
# Suportă: Suport multi-monitor, captură 60 FPS, control mouse/tastatură, 
#           mod ecrane full-screen și transmisie securizată.
# Dependențe: pip install websockets mss pyautogui pillow psutil pynput
# Compilare EXE: pyinstaller --onefile --windowed --name="MenV4_RC_Agent" client.py
# ==============================================================================

import asyncio
import json
import base64
import io
import os
import sys
import random
import platform
import subprocess
import threading
import tkinter as tk
from tkinter import ttk, messagebox
import websockets
from PIL import Image
import mss
import pyautogui
import psutil

pyautogui.FAILSAFE = False
pyautogui.PAUSE = 0.01

class MenV4RCAgent:
    def __init__(self):
        self.device_id = self.generate_device_id()
        self.pin = str(random.randint(100000, 999999))
        self.running = False
        self.ws = None
        self.selected_monitor = 1
        self.sct = mss.mss()

    def generate_device_id(self):
        # Generează un ID de 9 cifre (ex: 849 201 392)
        p1 = str(random.randint(100, 999))
        p2 = str(random.randint(100, 999))
        p3 = str(random.randint(100, 999))
        return f"{p1} {p2} {p3}"

    def get_system_info(self):
        return {
            "hostname": platform.node() or "PC-Remote",
            "os": f"{platform.system()} {platform.release()}",
            "arch": platform.machine(),
            "cpu_usage": psutil.cpu_percent(),
            "ram_usage": psutil.virtual_memory().percent,
            "monitors": len(self.sct.monitors) - 1,
            "ip": "Auto-Detected"
        }

    async def connect_to_relay(self, server_url):
        self.running = True
        try:
            async with websockets.connect(server_url) as websocket:
                self.ws = websocket
                
                # Înregistrare Agent în Server
                reg_msg = {
                    "type": "agent_register",
                    "device_id": self.device_id,
                    "pin": self.pin,
                    "info": self.get_system_info()
                }
                await websocket.send(json.dumps(reg_msg))

                # Pornire bucle paralele
                task_screen = asyncio.create_task(self.stream_screen_loop())
                task_listen = asyncio.create_task(self.listen_server_loop())

                await asyncio.gather(task_screen, task_listen)
        except Exception as e:
            print(f"Eroare conexiune: {e}")
            self.running = False

    async def stream_screen_loop(self):
        while self.running and self.ws:
            try:
                # Captură ecran curent
                monitors = self.sct.monitors
                mon_idx = min(self.selected_monitor, len(monitors) - 1)
                screenshot = self.sct.grab(monitors[mon_idx])

                img = Image.frombytes("RGB", screenshot.size, screenshot.bgra, "raw", "BGRX")
                img.thumbnail((1280, 720)) # Optimizare bandă internet

                buffer = io.BytesIO()
                img.save(buffer, format="JPEG", quality=65)
                b64_frame = base64.b64encode(buffer.getvalue()).decode('utf-8')

                frame_msg = {
                    "type": "screen_frame",
                    "device_id": self.device_id,
                    "frame": f"data:image/jpeg;base64,{b64_frame}",
                    "monitor": self.selected_monitor,
                    "width": screenshot.width,
                    "height": screenshot.height
                }
                await self.ws.send(json.dumps(frame_msg))
                await asyncio.sleep(0.06) # ~15-20 FPS stabil
            except Exception as e:
                await asyncio.sleep(0.1)

    async def listen_server_loop(self):
        while self.running and self.ws:
            try:
                message = await self.ws.recv()
                data = json.loads(message)
                msg_type = data.get("type")

                # Procesare Evenimente Mouse / Tastatură
                if msg_type == "input_event":
                    event = data.get("event")
                    action = event.get("type")
                    
                    if action == "mousemove":
                        rx, ry = event.get("x", 0), event.get("y", 0)
                        sw, sh = pyautogui.size()
                        pyautogui.moveTo(rx * sw, ry * sh)
                    elif action == "click":
                        btn = "left" if event.get("button") == 0 else "right"
                        pyautogui.click(button=btn)
                    elif action == "keydown":
                        key = event.get("key")
                        if key: pyautogui.press(key)

                elif msg_type == "switch_monitor":
                    self.selected_monitor = data.get("monitor", 1)

            except Exception as e:
                break

# Interfață Grafică Tkinter pentru Agent
def launch_gui():
    agent = MenV4RCAgent()

    root = tk.Tk()
    root.title("MenV4 RC - Agent Control Distanță")
    root.geometry("460x420")
    root.configure(bg="#0f172a")

    title_label = tk.Label(root, text="MenV4 RC Agent", font=("Helvetica", 18, "bold"), fg="#38bdf8", bg="#0f172a")
    title_label.pack(pady=(12, 2))

    subtitle = tk.Label(root, text="Sistem Profesional de Control de la Distanță", font=("Helvetica", 9), fg="#94a3b8", bg="#0f172a")
    subtitle.pack(pady=(0, 10))

    frame = tk.Frame(root, bg="#1e293b", bd=1, relief="solid")
    frame.pack(fill="both", expand=True, padx=20, pady=5)

    lbl_id_title = tk.Label(frame, text="ID-UL TĂU DE CONECTARE:", font=("Helvetica", 8, "bold"), fg="#cbd5e1", bg="#1e293b")
    lbl_id_title.pack(pady=(10, 2))

    lbl_id = tk.Label(frame, text=agent.device_id, font=("Courier", 22, "bold"), fg="#38bdf8", bg="#1e293b")
    lbl_id.pack()

    lbl_pin_title = tk.Label(frame, text="PAROLĂ / PIN TEMPORAR:", font=("Helvetica", 8, "bold"), fg="#cbd5e1", bg="#1e293b")
    lbl_pin_title.pack(pady=(8, 2))

    lbl_pin = tk.Label(frame, text=agent.pin, font=("Courier", 18, "bold"), fg="#f59e0b", bg="#1e293b")
    lbl_pin.pack()

    # Câmp Editare Adresă Server Host
    lbl_server_title = tk.Label(frame, text="ADRESĂ SERVER HOST (cPanel / VPS):", font=("Helvetica", 8, "bold"), fg="#94a3b8", bg="#1e293b")
    lbl_server_title.pack(pady=(12, 2))

    server_entry = tk.Entry(frame, font=("Courier", 10), bg="#0f172a", fg="#38bdf8", insertbackground="white", justify="center")
    server_entry.insert(0, "wss://rc.menv4.com/ws") # Pentru cPanel folosiți wss://rc.menv4.com/ws
    server_entry.pack(fill="x", padx=20, pady=2)

    status_lbl = tk.Label(frame, text="🔴 Deconectat", font=("Helvetica", 8, "bold"), fg="#ef4444", bg="#1e293b")
    status_lbl.pack(pady=4)

    def start_connection():
        url = server_entry.get().strip()
        if not url:
            messagebox.showwarning("Atenție", "Introduceți o adresă de server validă!")
            return
        status_lbl.config(text="🟡 Se conectează la server...", fg="#f59e0b")
        
        def bg_run():
            try:
                asyncio.run(agent.connect_to_relay(url))
            except Exception as e:
                status_lbl.config(text=f"🔴 Eroare: {e}", fg="#ef4444")

        t = threading.Thread(target=bg_run, daemon=True)
        t.start()
        status_lbl.config(text="🟢 Conectat & Activ la Server", fg="#22c65e")

    btn_connect = tk.Button(frame, text="🔌 Conectează la Server Host", font=("Helvetica", 9, "bold"), bg="#0284c7", fg="white", activebackground="#0369a1", cursor="hand2", command=start_connection)
    btn_connect.pack(pady=8, ipadx=10, ipady=3)

    # Autoconectare la pornire
    root.after(1000, start_connection)

    root.mainloop()

if __name__ == "__main__":
    launch_gui()
