#!/usr/bin/env python3
import sys, time, subprocess
import psutil
from collections import deque
from PyQt6.QtCore import Qt, QTimer, QThread, pyqtSignal, QPointF, QRectF, QPropertyAnimation, QEasingCurve, pyqtProperty
from PyQt6.QtGui import QFont, QPainter, QColor, QPen, QBrush, QPainterPath, QAction, QIcon
from PyQt6.QtWidgets import (QApplication, QMainWindow, QWidget, QVBoxLayout, QHBoxLayout, 
                             QLabel, QProgressBar, QSystemTrayIcon, QMenu, QGridLayout, 
                             QStackedWidget, QPushButton, QFrame, QScrollArea, QSlider)

# ==========================================
# THREAD DE DONNÉES (CPU, RAM, GPU, RESEAU)
# ==========================================
class UltimateMonitorThread(QThread):
    stats_updated = pyqtSignal(dict)

    def __init__(self):
        super().__init__()
        self.interval = 1000
        self.net_io = psutil.net_io_counters()
        self.last_time = time.time()

    def run(self):
        while True:
            current_time = time.time()
            dt = current_time - self.last_time
            new_net_io = psutil.net_io_counters()
            
            stats = {
                'cpu_temp': self.get_cpu_temp(),
                'cpu_percent': psutil.cpu_percent(interval=None),
                'cores': self.get_cores_temp(),
                'ram': psutil.virtual_memory().percent,
                'swap': psutil.swap_memory().percent,
                'disk': psutil.disk_usage('/').percent,
                'net_dl': (new_net_io.bytes_recv - self.net_io.bytes_recv) / dt / 1024 / 1024, # MB/s
                'net_ul': (new_net_io.bytes_sent - self.net_io.bytes_sent) / dt / 1024 / 1024, # MB/s
                'gpu': self.get_gpu_info()
            }
            
            self.net_io = new_net_io
            self.last_time = current_time
            self.stats_updated.emit(stats)
            self.msleep(self.interval)

    def get_cpu_temp(self):
        temps = psutil.sensors_temperatures()
        for name in ['coretemp', 'acpitz', 'cpu_thermal', 'k10temp']:
            if name in temps: return int(temps[name][0].current)
        return 40

    def get_cores_temp(self):
        cores = []
        temps = psutil.sensors_temperatures()
        if 'coretemp' in temps:
            cores = [(e.label, int(e.current)) for e in temps['coretemp'] if 'Core' in e.label]
        return cores if cores else [(f"Core {i}", 40) for i in range(psutil.cpu_count(logical=False) or 4)]

    def get_gpu_info(self):
        # Tente de récupérer les infos NVIDIA en priorité
        try:
            res = subprocess.check_output(['nvidia-smi', '--query-gpu=temperature.gpu,utilization.gpu', '--format=csv,noheader,nounits'], encoding='utf-8')
            temp, util = map(int, res.strip().split(', '))
            return {"name": "NVIDIA GPU", "temp": temp, "util": util}
        except:
            # Fallback sur les capteurs standards (AMD/Intel)
            temps = psutil.sensors_temperatures()
            if 'amdgpu' in temps:
                return {"name": "AMD GPU", "temp": int(temps['amdgpu'][0].current), "util": 0}
            return None

# ==========================================
# WIDGETS ANIMÉS ZORIN OS PRO
# ==========================================
class SmoothProgressBar(QProgressBar):
    def __init__(self, color="#1E88E5"):
        super().__init__()
        self.setFixedHeight(6)
        self.setTextVisible(False)
        self._color = color
        self._value = 0
        self.anim = QPropertyAnimation(self, b"animated_value")
        self.anim.setEasingCurve(QEasingCurve.Type.OutCubic)
        self.anim.setDuration(400)
        self.update_style()

    def update_style(self):
        self.setStyleSheet(f"""
            QProgressBar {{ background-color: #222222; border-radius: 3px; }}
            QProgressBar::chunk {{ background-color: {self._color}; border-radius: 3px; }}
        """)

    def set_color(self, color):
        self._color = color
        self.update_style()

    @pyqtProperty(int)
    def animated_value(self): return self._value

    @animated_value.setter
    def animated_value(self, val):
        self._value = val
        super().setValue(val)

    def set_smooth_value(self, val):
        self.anim.setStartValue(self._value)
        self.anim.setEndValue(val)
        self.anim.start()

class ModernGauge(QWidget):
    def __init__(self, title, color="#1E88E5"):
        super().__init__()
        self.setFixedSize(180, 180)
        self.value = 0
        self.title = title
        self.color = QColor(color)

    def set_value(self, val):
        self.value = val
        self.update()

    def set_color(self, hex_color):
        self.color = QColor(hex_color)
        self.update()

    def paintEvent(self, event):
        painter = QPainter(self)
        painter.setRenderHint(QPainter.RenderHint.Antialiasing)
        rect = QRectF(20, 20, 140, 140)

        painter.setPen(QPen(QColor("#2A2A2A"), 12, Qt.PenStyle.SolidLine, Qt.PenCapStyle.RoundCap))
        painter.drawArc(rect, 135 * 16, -270 * 16)

        span = int(-270 * (self.value / 100.0) * 16)
        painter.setPen(QPen(self.color, 12, Qt.PenStyle.SolidLine, Qt.PenCapStyle.RoundCap))
        painter.drawArc(rect, 135 * 16, span)

        painter.setPen(QColor("#FFFFFF"))
        painter.setFont(QFont("Inter", 32, QFont.Weight.Thin))
        painter.drawText(rect, Qt.AlignmentFlag.AlignCenter, f"{self.value}°")
        
        painter.setFont(QFont("Inter", 9, QFont.Weight.Bold))
        painter.setPen(QColor("#888888"))
        painter.drawText(QRectF(20, 140, 140, 30), Qt.AlignmentFlag.AlignCenter, self.title)

# ==========================================
# INTERFACE PRINCIPALE
# ==========================================
class UltimateApp(QMainWindow):
    def __init__(self):
        super().__init__()
        self.accent_color = "#1E88E5" # Bleu Zorin par défaut
        self.init_ui()
        self.init_tray()
        
        self.thread = UltimateMonitorThread()
        self.thread.stats_updated.connect(self.update_data)
        self.thread.start()

    def init_ui(self):
        self.setWindowTitle("7Cooler Ultimate")
        self.resize(850, 550)
        self.setStyleSheet("QMainWindow { background-color: #0E0E0E; color: #FFFFFF; }")

        main_widget = QWidget()
        self.setCentralWidget(main_widget)
        main_layout = QHBoxLayout(main_widget)
        main_layout.setContentsMargins(0, 0, 0, 0)
        main_layout.setSpacing(0)

        # --- MENU LATÉRAL ---
        sidebar = QFrame()
        sidebar.setFixedWidth(200)
        sidebar.setStyleSheet("background-color: #151515; border-right: 1px solid #222;")
        side_layout = QVBoxLayout(sidebar)
        side_layout.setContentsMargins(10, 30, 10, 30)

        brand = QLabel("7COOLER")
        brand.setFont(QFont("Inter", 16, QFont.Weight.Black))
        brand.setAlignment(Qt.AlignmentFlag.AlignCenter)
        brand.setStyleSheet("letter-spacing: 2px; margin-bottom: 30px;")
        side_layout.addWidget(brand)

        self.btn_dash = self.create_nav_btn("📊 Tableau de bord", 0)
        self.btn_hard = self.create_nav_btn("🌡️ Matériel & Capteurs", 1)
        self.btn_set = self.create_nav_btn("⚙️ Paramètres", 2)
        
        side_layout.addWidget(self.btn_dash)
        side_layout.addWidget(self.btn_hard)
        side_layout.addWidget(self.btn_set)
        side_layout.addStretch()

        # --- CONTENU CENTRAL (PAGES) ---
        self.stack = QStackedWidget()
        self.stack.setStyleSheet("background-color: #0E0E0E;")
        
        self.page_dash = self.build_dashboard()
        self.page_hard = self.build_hardware()
        self.page_set = self.build_settings()
        
        self.stack.addWidget(self.page_dash)
        self.stack.addWidget(self.page_hard)
        self.stack.addWidget(self.page_set)

        main_layout.addWidget(sidebar)
        main_layout.addWidget(self.stack)

        self.switch_page(0)

    def create_nav_btn(self, text, index):
        btn = QPushButton(text)
        btn.setFont(QFont("Inter", 10, QFont.Weight.Bold))
        btn.setCursor(Qt.CursorShape.PointingHandCursor)
        btn.setStyleSheet("""
            QPushButton { text-align: left; padding: 12px; border-radius: 8px; background: transparent; color: #888; border: none; }
            QPushButton:hover { background: #222; color: #FFF; }
        """)
        btn.clicked.connect(lambda: self.switch_page(index))
        return btn

    def switch_page(self, index):
        self.stack.setCurrentIndex(index)
        for i, btn in enumerate([self.btn_dash, self.btn_hard, self.btn_set]):
            if i == index:
                btn.setStyleSheet(f"text-align: left; padding: 12px; border-radius: 8px; background: {self.accent_color}; color: #FFF; font-weight: bold; border: none;")
            else:
                btn.setStyleSheet("text-align: left; padding: 12px; border-radius: 8px; background: transparent; color: #888; border: none;")

    # --- PAGE 1: DASHBOARD ---
    def build_dashboard(self):
        page = QWidget()
        layout = QVBoxLayout(page)
        layout.setContentsMargins(40, 40, 40, 40)
        
        title = QLabel("Vue d'ensemble")
        title.setFont(QFont("Inter", 22, QFont.Weight.Bold))
        layout.addWidget(title)

        # Jauges Hautes
        gauge_layout = QHBoxLayout()
        self.cpu_gauge = ModernGauge("CPU TEMP")
        self.gpu_gauge = ModernGauge("GPU TEMP")
        gauge_layout.addWidget(self.cpu_gauge)
        gauge_layout.addWidget(self.gpu_gauge)
        gauge_layout.addStretch()
        layout.addLayout(gauge_layout)

        layout.addSpacing(30)

        # Barres d'utilisation
        self.bars = {}
        for name, label in [('cpu', 'Charge CPU'), ('ram', 'Mémoire Vive'), ('swap', 'Fichier d\'échange'), ('disk', 'Stockage Principal')]:
            lbl = QLabel(f"{label}: 0%")
            lbl.setFont(QFont("Inter", 10))
            bar = SmoothProgressBar()
            self.bars[name] = {'lbl': lbl, 'bar': bar}
            layout.addWidget(lbl)
            layout.addWidget(bar)
            layout.addSpacing(10)
            
        layout.addStretch()
        return page

    # --- PAGE 2: HARDWARE ---
    def build_hardware(self):
        page = QWidget()
        layout = QVBoxLayout(page)
        layout.setContentsMargins(40, 40, 40, 40)
        
        title = QLabel("Capteurs Détaillés")
        title.setFont(QFont("Inter", 22, QFont.Weight.Bold))
        layout.addWidget(title)

        scroll = QScrollArea()
        scroll.setWidgetResizable(True)
        scroll.setStyleSheet("QScrollArea { border: none; background: transparent; }")
        
        content = QWidget()
        self.grid = QGridLayout(content)
        scroll.setWidget(content)
        layout.addWidget(scroll)
        
        # Réseau UI
        self.net_lbl = QLabel("Réseau: DL 0 MB/s | UL 0 MB/s")
        self.net_lbl.setFont(QFont("Inter", 12, QFont.Weight.Bold))
        self.net_lbl.setStyleSheet("color: #888;")
        layout.addWidget(self.net_lbl)
        
        return page

    # --- PAGE 3: SETTINGS ---
    def build_settings(self):
        page = QWidget()
        layout = QVBoxLayout(page)
        layout.setContentsMargins(40, 40, 40, 40)
        
        title = QLabel("Paramètres de l'Application")
        title.setFont(QFont("Inter", 22, QFont.Weight.Bold))
        layout.addWidget(title)

        # Thèmes
        theme_lbl = QLabel("Couleur d'accentuation")
        theme_lbl.setFont(QFont("Inter", 12, QFont.Weight.Bold))
        layout.addWidget(theme_lbl)

        colors_layout = QHBoxLayout()
        for c in ["#1E88E5", "#E53935", "#43A047", "#8E24AA", "#FDD835", "#FFFFFF"]:
            btn = QPushButton()
            btn.setFixedSize(40, 40)
            btn.setStyleSheet(f"background-color: {c}; border-radius: 20px; border: 2px solid #333;")
            btn.setCursor(Qt.CursorShape.PointingHandCursor)
            btn.clicked.connect(lambda checked, col=c: self.change_accent(col))
            colors_layout.addWidget(btn)
        colors_layout.addStretch()
        layout.addLayout(colors_layout)
        
        layout.addSpacing(30)

        # Intervalle
        speed_lbl = QLabel("Vitesse de rafraîchissement (ms)")
        speed_lbl.setFont(QFont("Inter", 12, QFont.Weight.Bold))
        layout.addWidget(speed_lbl)
        
        self.slider = QSlider(Qt.Orientation.Horizontal)
        self.slider.setRange(500, 3000)
        self.slider.setValue(1000)
        self.slider.setTickPosition(QSlider.TickPosition.TicksBelow)
        self.slider.setTickInterval(500)
        self.slider.valueChanged.connect(self.change_speed)
        layout.addWidget(self.slider)

        layout.addStretch()
        return page

    def change_accent(self, color):
        self.accent_color = color
        self.cpu_gauge.set_color(color)
        self.gpu_gauge.set_color(color)
        for b in self.bars.values(): b['bar'].set_color(color)
        self.switch_page(self.stack.currentIndex()) # Refresh menu color

    def change_speed(self, val):
        self.thread.interval = val

    def update_data(self, stats):
        # Update Dashboard
        self.cpu_gauge.set_value(stats['cpu_temp'])
        
        if stats['gpu']:
            self.gpu_gauge.set_value(stats['gpu']['temp'])
            self.gpu_gauge.title = stats['gpu']['name'].upper()
        else:
            self.gpu_gauge.set_value(0)
            self.gpu_gauge.title = "NO GPU"

        self.bars['cpu']['lbl'].setText(f"Charge CPU: {stats['cpu_percent']}%")
        self.bars['cpu']['bar'].set_smooth_value(int(stats['cpu_percent']))
        
        self.bars['ram']['lbl'].setText(f"Mémoire Vive: {stats['ram']}%")
        self.bars['ram']['bar'].set_smooth_value(int(stats['ram']))
        
        self.bars['swap']['lbl'].setText(f"Fichier d'échange: {stats['swap']}%")
        self.bars['swap']['bar'].set_smooth_value(int(stats['swap']))
        
        self.bars['disk']['lbl'].setText(f"Stockage Principal: {stats['disk']}%")
        self.bars['disk']['bar'].set_smooth_value(int(stats['disk']))

        # Update Network
        self.net_lbl.setText(f"Réseau: ↓ {stats['net_dl']:.2f} MB/s  |  ↑ {stats['net_ul']:.2f} MB/s")

        # Update Hardware Grid
        for i in reversed(range(self.grid.count())): 
            w = self.grid.itemAt(i).widget()
            if w: w.setParent(None)

        row, col = 0, 0
        for name, temp in stats['cores']:
            card = QFrame()
            card.setStyleSheet("background-color: #1A1A1A; border-radius: 10px; padding: 10px;")
            cl = QVBoxLayout(card)
            
            n = QLabel(name)
            n.setStyleSheet("color: #888; font-size: 11px;")
            t = QLabel(f"{temp}°C")
            t.setFont(QFont("Inter", 16, QFont.Weight.Bold))
            if temp > 85: t.setStyleSheet("color: #E53935;")
            
            cl.addWidget(n)
            cl.addWidget(t)
            self.grid.addWidget(card, row, col)
            
            col += 1
            if col > 3:
                col, row = 0, row + 1

        self.tray_icon.setToolTip(f"CPU: {stats['cpu_temp']}°C | RAM: {stats['ram']}%")

    def init_tray(self):
        self.tray_icon = QSystemTrayIcon(self)
        self.tray_icon.setIcon(QIcon.fromTheme("utilities-system-monitor"))
        menu = QMenu()
        show_action = QAction("Ouvrir 7Cooler Ultimate", self)
        show_action.triggered.connect(self.show)
        quit_action = QAction("Quitter", self)
        quit_action.triggered.connect(QApplication.instance().quit)
        menu.addAction(show_action)
        menu.addAction(quit_action)
        self.tray_icon.setContextMenu(menu)
        self.tray_icon.show()

    def closeEvent(self, event):
        event.ignore()
        self.hide()
        self.tray_icon.showMessage("7Cooler Ultimate", "Fonctionne en arrière-plan", QSystemTrayIcon.MessageIcon.Information, 2000)

if __name__ == "__main__":
    app = QApplication(sys.argv)
    QApplication.setQuitOnLastWindowClosed(False)
    app.setFont(QFont("Inter", 10))
    window = UltimateApp()
    window.show()
    sys.exit(app.exec())
