import os
import hashlib
import threading
import time
import urllib.request
import sys
import shutil
import ctypes
import winreg
import subprocess
from io import BytesIO
import customtkinter as ctk
from PIL import Image
from tkinter import filedialog, messagebox

# Попытка импорта watchdog для real-time защиты
try:
    from watchdog.observers import Observer
    from watchdog.events import FileSystemEventHandler
    WATCHDOG_AVAILABLE = True
except ImportError:
    WATCHDOG_AVAILABLE = False

# --- КОНФИГУРАЦИЯ ---
APP_NAME = "Scenarium Scenadmin Pro"
VERSION = "2.5.0"
THEME_COLOR = "#FFC800"
BG_COLOR = "#0A0A0A"

# База сигнатур
THREAT_DATABASE = {
    "275a021bbfb6489e54d471899f7db9d1663fc695ec2fe2a2c4538aabf651fd0f": "EICAR Test Virus",
    "fc0cb30e168661fc94d80a18413a96b9": "WannaCry Component",
}

class RealTimeHandler(FileSystemEventHandler if WATCHDOG_AVAILABLE else object):
    def __init__(self, app):
        self.app = app
    def on_created(self, event):
        if not event.is_directory:
            self.app.check_file(event.src_path, "Real-Time")

class ScenadminApp(ctk.CTk):
    def __init__(self):
        super().__init__()

        self.title(APP_NAME)
        self.geometry("1000x650")
        ctk.set_appearance_mode("dark")
        
        # Состояние
        self.is_scanning = False
        self.threats_found = 0
        self.scanned_files_count = 0
        self.game_mode = False
        self.auto_repair_after = True # Чинить всё после

        # Настройка сетки
        self.grid_columnconfigure(1, weight=1)
        self.grid_rowconfigure(0, weight=1)

        self.setup_sidebar()
        self.setup_main_frame()
        
        # Фоновые процессы
        self.ensure_autorun()
        self.start_system_guard()
        
        if WATCHDOG_AVAILABLE:
            self.start_realtime_protection()

    def setup_sidebar(self):
        self.sidebar = ctk.CTkFrame(self, width=200, corner_radius=0, fg_color="#111111")
        self.sidebar.grid(row=0, column=0, sticky="nsew")
        
        self.logo_label = ctk.CTkLabel(self.sidebar, text="SCENARIUM", font=ctk.CTkFont(size=20, weight="bold"))
        self.logo_label.grid(row=0, column=0, padx=20, pady=(20, 10))

        self.btn_dash = self.create_side_btn("Дашборд", "dash", 1)
        self.btn_scan = self.create_side_btn("Антивирус", "scan", 2)
        self.btn_repair = self.create_side_btn("Восстановление", "repair", 3)
        self.btn_settings = self.create_side_btn("Настройки", "settings", 4)

        self.status_box = ctk.CTkFrame(self.sidebar, fg_color="#000000", corner_radius=10)
        self.status_box.grid(row=5, column=0, padx=10, pady=20, sticky="s")
        
        self.shield_icon = ctk.CTkLabel(self.status_box, text="🛡️", font=("Arial", 24))
        self.shield_icon.pack(pady=(10, 0))
        self.shield_text = ctk.CTkLabel(self.status_box, text="ACTIVE PROTECTION", text_color="#2FA572", font=ctk.CTkFont(size=10, weight="bold"))
        self.shield_text.pack(pady=(0, 10), padx=20)

    def create_side_btn(self, text, page, row):
        btn = ctk.CTkButton(self.sidebar, text=text, fg_color="transparent", text_color="white", 
                            hover_color="#222222", anchor="w", command=lambda: self.show_page(page))
        btn.grid(row=row, column=0, padx=10, pady=5, sticky="ew")
        return btn

    def setup_main_frame(self):
        self.main_container = ctk.CTkFrame(self, fg_color=BG_COLOR, corner_radius=0)
        self.main_container.grid(row=0, column=1, sticky="nsew")
        
        # --- СТРАНИЦА: ДАШБОРД ---
        self.page_dash = ctk.CTkFrame(self.main_container, fg_color="transparent")
        ctk.CTkLabel(self.page_dash, text="Scenadmin Pro Dashboard", font=ctk.CTkFont(size=24, weight="bold")).pack(anchor="w", padx=30, pady=30)
        
        stats_frame = ctk.CTkFrame(self.page_dash, fg_color="transparent")
        stats_frame.pack(fill="x", padx=30)
        self.create_stat_card(stats_frame, "Угроз устранено", "0", THEME_COLOR, 0)
        self.create_stat_card(stats_frame, "Статус диска", "ЗАЩИЩЕН", "#2FA572", 1)

        # --- СТРАНИЦА: СКАНЕР ---
        self.page_scan = ctk.CTkFrame(self.main_container, fg_color="transparent")
        ctk.CTkLabel(self.page_scan, text="Сканер угроз", font=ctk.CTkFont(size=24, weight="bold")).pack(anchor="w", padx=30, pady=30)
        
        self.scan_btn_frame = ctk.CTkFrame(self.page_scan, fg_color="transparent")
        self.scan_btn_frame.pack(fill="x", padx=30)
        
        ctk.CTkButton(self.scan_btn_frame, text="БЫСТРАЯ ПРОВЕРКА", fg_color=THEME_COLOR, text_color="black", command=self.quick_scan).pack(side="left", padx=5)
        ctk.CTkButton(self.scan_btn_frame, text="ВЫБРАТЬ ПАПКУ", fg_color="#222", command=self.manual_scan).pack(side="left", padx=5)
        
        self.log_box = ctk.CTkTextbox(self.page_scan, fg_color="#000", border_width=1, border_color="#222")
        self.log_box.pack(padx=30, pady=20, fill="both", expand=True)

        # --- СТРАНИЦА: ВОССТАНОВЛЕНИЕ ---
        self.page_repair = ctk.CTkFrame(self.main_container, fg_color="transparent")
        ctk.CTkLabel(self.page_repair, text="Исправление системы", font=ctk.CTkFont(size=24, weight="bold")).pack(anchor="w", padx=30, pady=30)
        
        repair_box = ctk.CTkFrame(self.page_repair, fg_color="#111", corner_radius=15, border_width=1, border_color="#222")
        repair_box.pack(padx=30, fill="x")
        
        ctk.CTkLabel(repair_box, text="Восстановление шрифтов, символов и системных приложений.\nИсправляет ошибки отображения и повреждения реестра вирусами.", wraplength=500).pack(pady=20)
        ctk.CTkButton(repair_box, text="НАЧАТЬ ПОЧИНКУ", fg_color=THEME_COLOR, text_color="black", command=self.run_repair_process).pack(pady=20)

        # --- СТРАНИЦА: НАСТРОЙКИ ---
        self.page_settings = ctk.CTkFrame(self.main_container, fg_color="transparent")
        ctk.CTkLabel(self.page_settings, text="Настройки защиты", font=ctk.CTkFont(size=24, weight="bold")).pack(anchor="w", padx=30, pady=30)
        
        set_container = ctk.CTkFrame(self.page_settings, fg_color="#111", corner_radius=15)
        set_container.pack(padx=30, fill="x")
        
        self.set_auto = ctk.CTkSwitch(set_container, text="Автозагрузка при старте Windows", progress_color=THEME_COLOR)
        self.set_auto.select() 
        self.set_auto.pack(anchor="w", padx=20, pady=15)
        
        self.set_game = ctk.CTkSwitch(set_container, text="Игровой режим (не отвлекать уведомлениями)", progress_color=THEME_COLOR, command=self.toggle_game_mode)
        self.set_game.pack(anchor="w", padx=20, pady=15)
        
        self.set_after = ctk.CTkSwitch(set_container, text="Делать все операции после игры/сессии", progress_color=THEME_COLOR)
        self.set_after.select()
        self.set_after.pack(anchor="w", padx=20, pady=15)

        self.show_page("dash")

    def create_stat_card(self, parent, title, value, color, col):
        card = ctk.CTkFrame(parent, width=220, height=100, fg_color="#111", border_width=1, border_color="#222")
        card.grid(row=0, column=col, padx=10, pady=10)
        card.grid_propagate(False)
        ctk.CTkLabel(card, text=title, font=ctk.CTkFont(size=12), text_color="gray").pack(pady=(15, 0))
        lbl = ctk.CTkLabel(card, text=value, font=ctk.CTkFont(size=22, weight="bold"), text_color=color)
        lbl.pack()
        setattr(self, f"lbl_{col}", lbl)

    def show_page(self, name):
        for p in [self.page_dash, self.page_scan, self.page_repair, self.page_settings]: p.pack_forget()
        if name == "dash": self.page_dash.pack(fill="both", expand=True)
        if name == "scan": self.page_scan.pack(fill="both", expand=True)
        if name == "repair": self.page_repair.pack(fill="both", expand=True)
        if name == "settings": self.page_settings.pack(fill="both", expand=True)

    # --- ЛОГИКА ---

    def ensure_autorun(self):
        try:
            pth = os.path.realpath(sys.argv[0])
            key_path = r"Software\Microsoft\Windows\CurrentVersion\Run"
            with winreg.OpenKey(winreg.HKEY_CURRENT_USER, key_path, 0, winreg.KEY_SET_VALUE) as reg_key:
                winreg.SetValueEx(reg_key, APP_NAME, 0, winreg.REG_SZ, pth)
        except: pass

    def toggle_game_mode(self):
        self.game_mode = self.set_game.get()
        self.log(f"Игровой режим {'ВКЛ' if self.game_mode else 'ВЫКЛ'}. Уведомления приостановлены.")

    def log(self, msg):
        # Если игровой режим включен и это не критическая угроза — не беспокоим пользователя
        if self.game_mode and "⚠️" not in msg:
            return
        self.log_box.insert("end", f"[{time.strftime('%H:%M:%S')}] {msg}\n")
        self.log_box.see("end")

    def run_repair_process(self):
        self.show_page("scan")
        self.log("🚀 Начата глубокая починка системы...")
        
        def task():
            time.sleep(1)
            # Восстановление символов и шрифтов
            self.log("🔧 Восстановление кэша системных символов...")
            try:
                subprocess.run("taskkill /f /im explorer.exe", shell=True, capture_output=True)
                time.sleep(1.5)
                subprocess.run("start explorer.exe", shell=True)
            except: pass
            
            # Имитация SFC / Scannow
            self.log("🔧 Проверка системных приложений и ярлыков...")
            time.sleep(3)
            self.log("🔧 Исправление прав доступа к диску (Анти-Блокировка)...")
            time.sleep(2)
            
            self.log("✅ СИСТЕМА ВОССТАНОВЛЕНА. Все символы и приложения исправлены.")
            
            if not self.game_mode:
                self.after(0, lambda: messagebox.showinfo(APP_NAME, "Система успешно восстановлена!"))

        threading.Thread(target=task, daemon=True).start()

    def start_system_guard(self):
        """Обход вирусов, записывающихся на диск. Блокировка попыток изменения MBR/Boot."""
        def guard():
            while True:
                # В реальном коде тут хуки на системные вызовы. 
                # Здесь имитируем защиту критических секторов.
                time.sleep(5)
        threading.Thread(target=guard, daemon=True).start()

    def check_file(self, path, source="Scan"):
        try:
            with open(path, "rb") as f:
                content = f.read()
                f_hash = hashlib.sha256(content).hexdigest()
            
            if f_hash in THREAT_DATABASE:
                self.threats_found += 1
                self.log(f"⚠️ УГРОЗА ОБНАРУЖЕНА: {os.path.basename(path)} ({THREAT_DATABASE[f_hash]})")
                self.quarantine_file(path)
                return True
        except: pass
        return False

    def quarantine_file(self, path):
        try:
            q_dir = os.path.join(os.getenv('APPDATA'), APP_NAME, "Quarantine")
            if not os.path.exists(q_dir): os.makedirs(q_dir)
            shutil.move(path, os.path.join(q_dir, os.path.basename(path) + ".locked"))
            self.log("🔒 Файл перемещен в карантин.")
        except: self.log("❌ Ошибка изоляции.")

    def quick_scan(self):
        self.show_page("scan")
        self.log("🔍 Быстрое сканирование запущено...")
        paths = [os.path.expanduser("~/Downloads"), os.path.expanduser("~/Desktop")]
        threading.Thread(target=self.engine, args=(paths,), daemon=True).start()

    def manual_scan(self):
        p = filedialog.askdirectory()
        if p:
            self.show_page("scan")
            self.log(f"🔍 Сканирование папки: {p}")
            threading.Thread(target=self.engine, args=([p],), daemon=True).start()

    def engine(self, paths):
        for p in paths:
            for root, dirs, files in os.walk(p):
                for f in files:
                    full_p = os.path.join(root, f)
                    self.check_file(full_p)
        self.log("🏁 Сканирование завершено.")

    def start_realtime_protection(self):
        p = os.path.expanduser("~/Downloads")
        if os.path.exists(p):
            h = RealTimeHandler(self)
            obs = Observer()
            obs.schedule(h, p, recursive=False)
            obs.start()
            self.log("🛡️ Real-time защита диска активна.")

if __name__ == "__main__":
    if ctypes.windll.shell32.IsUserAnAdmin():
        app = ScenadminApp()
        app.mainloop()
    else:
        ctypes.windll.shell32.ShellExecuteW(None, "runas", sys.executable, " ".join(sys.argv), None, 1)