import customtkinter as ctk
from tkinter import messagebox
import os
import sys
import yaml
import hashlib
import logging
import random
import time
import math
import psutil
import subprocess

# Os environment 
APPDATA = os.getenv('APPDATA') or os.path.expanduser("~")
PROGRAM_FOLDER = os.path.join(APPDATA, "Make_It_Simple")
SETTINGS_PATH = os.path.join(PROGRAM_FOLDER, "settings.yml")
SECRETS_PATH = os.path.join(PROGRAM_FOLDER, "secrets.yml")
EXTENTIONS_FOLDER = os.path.join(PROGRAM_FOLDER, "extensions")

os.makedirs(PROGRAM_FOLDER, exist_ok=True)
os.makedirs(EXTENTIONS_FOLDER, exist_ok=True)

# Configure logging
logging.basicConfig(
    filename=f"{APPDATA}/Make_It_Simple/error.log",
    level=logging.ERROR,
    format="%(asctime)s | %(levelname)s | %(message)s"
)

def tum_hatalari_yakala(exc_type, exc_value, exc_traceback):
    logging.critical(
        "YAKALANMAYAN KRİTİK HATA",
        exc_info=(exc_type, exc_value, exc_traceback)
    )

sys.excepthook = tum_hatalari_yakala

# Default settings
default_settings = {
    "theme": "dark",
    "auto_update": True
}

def set_settings_to_default():
    ctk.set_appearance_mode("dark")
    with open(SETTINGS_PATH, 'w') as f:
        yaml.dump(default_settings, f)

def reset_secrets(token: str) -> str:
    """Tokeni SHA256 ile hashler."""
    return hashlib.sha256(str(token).encode()).hexdigest()

FIRST_RUN = False
READABLE_TOKEN = None  # Kullanıcıya gösterilecek ilk token

def load_settings():
    global settings
    if not os.path.exists(SETTINGS_PATH):
        set_settings_to_default()
    try:
        with open(SETTINGS_PATH, "r") as f:
            settings = yaml.safe_load(f) or default_settings
    except Exception:
        logging.exception("settings.yml okunamadı, varsayılan yüklendi")
        settings = default_settings
    ctk.set_appearance_mode(settings.get("theme", "dark"))

def load_secrets():
    global secrets, FIRST_RUN, READABLE_TOKEN
    if not os.path.exists(SECRETS_PATH):
        # İlk kez çalışıyorsa: kullanıcı için rastgele bir token üret
        FIRST_RUN = True
        READABLE_TOKEN = random.randint(100000, 999999)
        token_hash = reset_secrets(READABLE_TOKEN)
        secrets = {"token": token_hash}
        with open(SECRETS_PATH, "w") as f:
            yaml.dump(secrets, f)
    else:
        try:
            with open(SECRETS_PATH, "r") as f:
                secrets = yaml.safe_load(f) or {}
        except Exception:
            logging.exception("secrets.yml okunamadı")
            secrets = {}

# =========================
# Güvenlik: Token doğrulama
# =========================
def check_token(action_text: str) -> bool:
    """
    Her kritik işlemden önce token ister.
    Token doğruysa True, yanlışsa False döner.
    """
    if "token" not in secrets:
        messagebox.showerror("Güvenlik Hatası", "Güvenlik tokeni bulunamadı.")
        return False

    # CustomTkinter Input Dialog
    dialog = ctk.CTkInputDialog(
        text=f"{action_text} için güvenlik tokenini girin:",
        title="Güvenlik Doğrulama"
    )
    entered = dialog.get_input()

    if not entered:
        return False

    if reset_secrets(entered) == secrets.get("token"):
        return True

    messagebox.showerror("Hatalı Token", "Güvenlik tokeni yanlış.")
    return False


# Starting point
load_settings()
load_secrets()

app = ctk.CTk()
app.withdraw()  # Ana pencere sadece yüklenme/splash bittikten sonra açılacak

# İlk çalıştırmada tokeni kullanıcıya göster
if FIRST_RUN and READABLE_TOKEN is not None:
    # Tk arayüzü hazır olsun diye küçük bir gecikme ile gösteriyoruz
    app.after(100, lambda: messagebox.showinfo(
        "Güvenlik Tokeni",
        f"İlk güvenlik tokeniniz:\n\n{READABLE_TOKEN}\n\nBu kodu bir yere not etmeyi unutmayın!"
    ))

# =========================
# CTK ÜST MENÜ (PROGRAM MENÜSÜ)
# =========================
top_menu = ctk.CTkFrame(app, height=50, fg_color="#1f1f1f")
top_menu.pack(fill="x")

menu_title = ctk.CTkLabel(
    top_menu,
    text="Make It Simple",
    font=ctk.CTkFont(size=18, weight="bold")
)
menu_title.pack(side="left", padx=15)

# Menü Fonksiyonları (TOKEN KORUMALI)
def close_ps():
    if not check_token("Bilgisayarı kapatmak"):
        return
    messagebox.showinfo("Kapanış", "Bilgisayar 1 saniye içinde kapanacak.")
    os.system("shutdown /s /t 1")

def restart_ps():
    if not check_token("Bilgisayarı yeniden başlatmak"):
        return
    messagebox.showinfo("Yeniden Başlatma", "Bilgisayar yeniden başlatılacak.")
    os.system("shutdown /r /t 1")

def sleep_ps():
    if not check_token("Bilgisayarı uyku moduna almak"):
        return
    messagebox.showinfo("Uyku Modu", "Bilgisayar uyku moduna geçiyor.")
    os.system("rundll32.exe powrprof.dll,SetSuspendState 0,1,0")

def close_process():
    if not check_token("Programdan çıkmak"):
        return
    app.destroy()

# KAPAT / YENİDEN BAŞLAT / UYKU / ÇIKIŞ BUTONLARI
ctk.CTkButton(top_menu, text="Kapat", command=close_ps, width=90).pack(side="right", padx=5, pady=8)
ctk.CTkButton(top_menu, text="Yeniden Başlat", command=restart_ps, width=130).pack(side="right", padx=5)
ctk.CTkButton(top_menu, text="Uyku", command=sleep_ps, width=90).pack(side="right", padx=5)
ctk.CTkButton(top_menu, text="Çıkış", command=close_process, width=90).pack(side="right", padx=10)


# =========================
# YÜKLENME (SPLASH) EKRANI
# =========================
load_screen = ctk.CTkToplevel(app)
load_screen.geometry("400x200")
load_screen.title("Yükleniyor...")
load_screen.resizable(False, False)

load_frame = ctk.CTkFrame(load_screen)
load_frame.pack(expand=True, fill="both", padx=20, pady=20)

canvas = ctk.CTkCanvas(load_frame, width=200, height=100, bg="#1a1a1a", highlightthickness=0)
canvas.pack(pady=20)

angle = 0
ANIMATION_WAIT_TIME = 3000
start_time = time.time()

def animate_loader():
    global angle, start_time

    if (time.time() - start_time) * 1000 > ANIMATION_WAIT_TIME:
        load_screen.withdraw()     # Splash gizlenir
        app.deiconify()            # Ana pencere açılır
        return

    canvas.delete("all")
    x0, y0 = 100, 50
    r = 25

    for i in range(10):
        rad = math.radians(angle + i * 36)
        x = x0 + r * math.cos(rad)
        y = y0 + r * math.sin(rad)
        canvas.create_oval(x-4, y-4, x+4, y+4, fill="#00aaff", outline="")

    angle = (angle + 8) % 360
    load_screen.after(40, animate_loader)

animate_loader()


# =========================
# ANA PENCERE İÇERİĞİ
# =========================
app.title("Make It Simple")
app.geometry("800x600")

main_frame = ctk.CTkFrame(app)
main_frame.pack(expand=True, fill="both", padx=20, pady=20)

ctk.CTkLabel(
    main_frame,
    text="İşletim Sistemi Kontrol Paneli",
    font=ctk.CTkFont(size=20, weight="bold")
).pack(pady=20)

# Sistem bilgi label'ları
ram_label = ctk.CTkLabel(main_frame, font=ctk.CTkFont(size=16))
cpu_label = ctk.CTkLabel(main_frame, font=ctk.CTkFont(size=16))
disk_label = ctk.CTkLabel(main_frame, font=ctk.CTkFont(size=16))
battery_label = ctk.CTkLabel(main_frame, font=ctk.CTkFont(size=16))

ram_label.pack(pady=5)
cpu_label.pack(pady=5)
disk_label.pack(pady=5)
battery_label.pack(pady=5)

# CANLI SİSTEM GÜNCELLEME
def update_system():
    try:
        ram = psutil.virtual_memory().percent
        cpu = psutil.cpu_percent()
        disk = psutil.disk_usage('C:/').percent
    except Exception as e:
        logging.exception("Sistem bilgisi okunamadı")
        ram = cpu = disk = 0

    ram_label.configure(text=f"RAM Kullanımı: {ram}%")
    cpu_label.configure(text=f"CPU Kullanımı: {cpu}%")
    disk_label.configure(text=f"Disk Kullanımı: {disk}%")

    try:
        battery = psutil.sensors_battery()
        if battery:
            battery_label.configure(
                text=f"Batarya: {battery.percent}% {'(Şarj Oluyor)' if battery.power_plugged else ''}"
            )
        else:
            battery_label.configure(text="Batarya: Yok")
    except Exception:
        battery_label.configure(text="Batarya bilgisi okunamadı")

    app.after(1000, update_system)

update_system()

# ZAMANLI KAPATMA (TOKEN KORUMALI)
shutdown_entry = ctk.CTkEntry(main_frame, placeholder_text="Kapanma süresi (saniye)")
shutdown_entry.pack(pady=10)

def schedule_shutdown():
    if not check_token("Zamanlı kapatma ayarlamak"):
        return
    try:
        sec = int(shutdown_entry.get())
        if sec < 1:
            raise ValueError
        subprocess.run(f"shutdown /s /t {sec}", shell=True)
        messagebox.showinfo("Zamanlı Kapatma", f"Bilgisayar {sec} saniye sonra kapanacak.")
    except Exception:
        messagebox.showwarning("Hata", "Lütfen geçerli bir saniye değeri girin.")

ctk.CTkButton(main_frame, text="Zamanlı Kapat", command=schedule_shutdown).pack(pady=10)

app.mainloop()
