import sys
import os
import re
import json
import time
import urllib.parse
import urllib.request
from PyQt6.QtWidgets import (
    QApplication, QMainWindow, QWidget, QVBoxLayout, QHBoxLayout,
    QLabel, QPushButton, QLineEdit, QFrame, QMessageBox, QCheckBox,
    QFileDialog
)
from PyQt6.QtCore import QProcess, Qt, QTimer
from PyQt6.QtGui import QFont

# -----------------------------------------------------------
# הגדרות נתיבים כלליות
# -----------------------------------------------------------
SCRIPT_DIR = os.path.dirname(os.path.abspath(sys.argv[0]))
SETTINGS_FILE = os.path.join(SCRIPT_DIR, "control_panel_config.json")
NETFREE_CERT = r"C:\ProgramData\NetFree\CA\netfree-ca-bundle-curl.crt"

# הגדרות הרצה אוטומטית עם עליית המערכת
STARTUP_DIR = os.path.join(os.environ.get("APPDATA", ""), r"Microsoft\Windows\Start Menu\Programs\Startup")
BAT_NAME = "SmartHomeControlPanel.bat"
BAT_PATH = os.path.join(STARTUP_DIR, BAT_NAME)

class SmartHomeControlPanel(QMainWindow):
    def __init__(self):
        super().__init__()
        self.setWindowTitle("מרכז שליטה אוטומטי - עדכון שלוחות בית חכם")
        self.resize(540, 700)
        self.setLayoutDirection(Qt.LayoutDirection.RightToLeft)

        self.ha_process = None
        self.cf_process = None
        self.current_url = ""

        self.init_ui()
        self.apply_styles()
        self.load_settings()

        # הגדרת ניטור מצב שינה / התעוררות המחשב
        self.last_keepalive = time.time()
        self.sleep_monitor_timer = QTimer(self)
        self.sleep_monitor_timer.timeout.connect(self.monitor_sleep_wakeup)
        self.sleep_monitor_timer.start(5000) # בדיקה כל 5 שניות

        if "--autostart" in sys.argv:
            QTimer.singleShot(1500, self.start_all)

    def init_ui(self):
        main_widget = QWidget()
        self.setCentralWidget(main_widget)
        main_layout = QVBoxLayout(main_widget)
        main_layout.setSpacing(15)
        main_layout.setContentsMargins(20, 20, 20, 20)

        # כותרת ראשית
        title = QLabel("🤖 מרכז שליטה - הבית החכם")
        title.setFont(QFont("Segoe UI", 16, QFont.Weight.Bold))
        title.setAlignment(Qt.AlignmentFlag.AlignCenter)
        main_layout.addWidget(title)

        # -----------------------------------------------------------
        # כרטיסייה 1: Home Assistant
        # -----------------------------------------------------------
        ha_card = QFrame()
        ha_card.setObjectName("card")
        ha_layout = QVBoxLayout(ha_card)

        ha_header = QHBoxLayout()
        ha_title = QLabel("מנוע Home Assistant")
        ha_title.setFont(QFont("Segoe UI", 12, QFont.Weight.Bold))
        self.ha_status = QLabel("● כבוי")
        self.ha_status.setObjectName("status_off")
        
        ha_header.addWidget(ha_title)
        ha_header.addStretch()
        ha_header.addWidget(self.ha_status)
        ha_layout.addLayout(ha_header)

        ha_btns = QHBoxLayout()
        self.btn_start_ha = QPushButton("הפעל HA")
        self.btn_start_ha.clicked.connect(self.start_ha)
        
        self.btn_stop_ha = QPushButton("כבה HA")
        self.btn_stop_ha.setObjectName("btn_danger")
        self.btn_stop_ha.clicked.connect(self.stop_ha)

        btn_browser = QPushButton("פתח בדפדפן 🌐")
        btn_browser.setObjectName("btn_secondary")
        btn_browser.clicked.connect(lambda: os.system("start http://127.0.0.1:8123"))

        ha_btns.addWidget(self.btn_start_ha)
        ha_btns.addWidget(self.btn_stop_ha)
        ha_btns.addWidget(btn_browser)
        ha_layout.addLayout(ha_btns)

        main_layout.addWidget(ha_card)

        # -----------------------------------------------------------
        # כרטיסייה 2: הגדרות נתיבים ומערכת
        # -----------------------------------------------------------
        settings_card = QFrame()
        settings_card.setObjectName("card")
        settings_layout = QVBoxLayout(settings_card)

        settings_title = QLabel("⚙️ הגדרות מערכת ונתיבים")
        settings_title.setFont(QFont("Segoe UI", 12, QFont.Weight.Bold))
        settings_layout.addWidget(settings_title)

        # שורת בחירת תיקיית HassWP
        path_layout = QHBoxLayout()
        self.hass_path_input = QLineEdit()
        self.hass_path_input.setPlaceholderText("נתיב לתיקיית HassWP (למשל: C:\\HassWP)")
        
        btn_browse = QPushButton("בחר תיקייה 📂")
        btn_browse.setObjectName("btn_secondary")
        btn_browse.clicked.connect(self.browse_hass_folder)
        
        path_layout.addWidget(self.hass_path_input)
        path_layout.addWidget(btn_browse)
        settings_layout.addLayout(path_layout)

        # שורת פרטי ימות המשיח
        inputs_layout = QHBoxLayout()
        self.yemot_num_input = QLineEdit()
        self.yemot_num_input.setPlaceholderText("מספר מערכת (למשל: 0771234567)")

        self.yemot_pass_input = QLineEdit()
        self.yemot_pass_input.setPlaceholderText("סיסמה")
        self.yemot_pass_input.setEchoMode(QLineEdit.EchoMode.Password)

        inputs_layout.addWidget(self.yemot_num_input)
        inputs_layout.addWidget(self.yemot_pass_input)
        settings_layout.addLayout(inputs_layout)

        # שורת הגדרת השלוחות לעדכון
        extensions_layout = QHBoxLayout()
        self.extensions_input = QLineEdit()
        self.extensions_input.setPlaceholderText("רשימת שלוחות לעדכון (למשל: 1, 9, 2/1, 2/2)")
        
        btn_save_settings = QPushButton("שמור הגדרות 💾")
        btn_save_settings.setObjectName("btn_success")
        btn_save_settings.clicked.connect(self.save_settings)
        
        extensions_layout.addWidget(self.extensions_input)
        extensions_layout.addWidget(btn_save_settings)
        settings_layout.addLayout(extensions_layout)

        main_layout.addWidget(settings_card)

        # -----------------------------------------------------------
        # כרטיסייה 3: מנהרת Cloudflare
        # -----------------------------------------------------------
        cf_card = QFrame()
        cf_card.setObjectName("card")
        cf_layout = QVBoxLayout(cf_card)

        cf_header = QHBoxLayout()
        cf_title = QLabel("מנהרת תקשורת (חיבור לטלפון)")
        cf_title.setFont(QFont("Segoe UI", 12, QFont.Weight.Bold))
        self.cf_status = QLabel("● כבוי")
        self.cf_status.setObjectName("status_off")

        cf_header.addWidget(cf_title)
        cf_header.addStretch()
        cf_header.addWidget(self.cf_status)
        cf_layout.addLayout(cf_header)

        cf_btns = QHBoxLayout()
        self.btn_start_cf = QPushButton("הפעל מנהרה")
        self.btn_start_cf.clicked.connect(self.start_cf)

        self.btn_stop_cf = QPushButton("כבה מנהרה")
        self.btn_stop_cf.setObjectName("btn_danger")
        self.btn_stop_cf.clicked.connect(self.stop_cf)

        cf_btns.addWidget(self.btn_start_cf)
        cf_btns.addWidget(self.btn_stop_cf)
        cf_layout.addLayout(cf_btns)

        # שדה הצגת הקישור והסטטוס
        url_layout = QHBoxLayout()
        self.url_input = QLineEdit()
        self.url_input.setPlaceholderText("הקישור והעדכון לימות המשיח יופיעו כאן...")
        self.url_input.setReadOnly(True)
        url_layout.addWidget(self.url_input)
        cf_layout.addLayout(url_layout)

        # כפתור לעדכון ידני כפוי
        self.btn_force_update = QPushButton("סנכרן ידנית לימות המשיח 🔄")
        self.btn_force_update.setObjectName("btn_secondary")
        self.btn_force_update.clicked.connect(self.force_update_yemot)
        cf_layout.addWidget(self.btn_force_update)

        main_layout.addWidget(cf_card)

        # -----------------------------------------------------------
        # שליטה גלובלית והגדרות מערכת
        # -----------------------------------------------------------
        global_card = QFrame()
        global_card.setObjectName("card")
        global_layout = QVBoxLayout(global_card)

        btns_layout = QHBoxLayout()
        btn_start_all = QPushButton("🚀 הפעל את כל המערכת")
        btn_start_all.setObjectName("btn_success")
        btn_start_all.clicked.connect(self.start_all)

        btn_stop_all = QPushButton("🛑 כבה את כל המערכת")
        btn_stop_all.setObjectName("btn_danger")
        btn_stop_all.clicked.connect(self.stop_all)

        btns_layout.addWidget(btn_start_all)
        btns_layout.addWidget(btn_stop_all)
        global_layout.addLayout(btns_layout)

        self.chk_startup = QCheckBox("הפעל אוטומטית עם הדלקת המחשב")
        self.chk_startup.setChecked(self.is_startup_enabled())
        self.chk_startup.toggled.connect(self.toggle_startup)
        global_layout.addWidget(self.chk_startup, alignment=Qt.AlignmentFlag.AlignCenter)

        main_layout.addWidget(global_card)
        main_layout.addStretch()

    # --- לוגיקה ---

    def monitor_sleep_wakeup(self):
        now = time.time()
        drift = now - self.last_keepalive
        self.last_keepalive = now

        if drift > 15:
            print(f"מערכת זיהתה התעוררות ממצב שינה. מבצע אתחול שירותים...")
            self.cf_status.setText("● התעוררות (מנקה תהליכים)...")
            self.cf_status.setObjectName("status_warning")
            self.cf_status.setStyle(self.cf_status.style())
            self.ha_status.setText("● מאתחל...")
            self.ha_status.setObjectName("status_warning")
            self.ha_status.setStyle(self.ha_status.style())
            
            self.stop_all()
            QTimer.singleShot(8000, self.start_all)

    def browse_hass_folder(self):
        folder = QFileDialog.getExistingDirectory(self, "בחר את תיקיית HassWP")
        if folder:
            self.hass_path_input.setText(os.path.normpath(folder))

    def load_settings(self):
        if os.path.exists(SETTINGS_FILE):
            try:
                with open(SETTINGS_FILE, 'r', encoding='utf-8') as f:
                    data = json.load(f)
                    self.hass_path_input.setText(data.get("hass_wp_dir", ""))
                    self.yemot_num_input.setText(data.get("system_number", ""))
                    self.yemot_pass_input.setText(data.get("password", ""))
                    self.extensions_input.setText(data.get("extensions", "1, 9, 2/1"))
            except Exception as e:
                print(f"שגיאה בטעינת הגדרות: {e}")
        else:
            self.extensions_input.setText("1, 9, 2/1")

    def save_settings(self):
        data = {
            "hass_wp_dir": self.hass_path_input.text().strip(),
            "system_number": self.yemot_num_input.text().strip(),
            "password": self.yemot_pass_input.text().strip(),
            "extensions": self.extensions_input.text().strip()
        }
        try:
            with open(SETTINGS_FILE, 'w', encoding='utf-8') as f:
                json.dump(data, f, ensure_ascii=False, indent=4)
            QMessageBox.information(self, "הצלחה", "ההגדרות נשמרו בהצלחה!")
        except Exception as e:
            QMessageBox.critical(self, "שגיאה", f"לא ניתן לשמור: {e}")

    def get_hass_wp_dir(self):
        path = self.hass_path_input.text().strip()
        if not path or not os.path.exists(path):
            QMessageBox.warning(self, "שגיאה בנתיב", "נתיב תיקיית HassWP אינו מוגדר או אינו קיים במערכת.")
            return None
        return path

    def start_ha(self):
        base_dir = self.get_hass_wp_dir()
        if not base_dir:
            return

        hass_cmd = os.path.join(base_dir, "hass.cmd")
        if not os.path.exists(hass_cmd):
            QMessageBox.critical(self, "שגיאה", f"לא נמצא קובץ הפעלה בנתיב: {hass_cmd}")
            return

        if self.ha_process is None or self.ha_process.state() == QProcess.ProcessState.NotRunning:
            self.ha_process = QProcess(self)
            self.ha_process.setWorkingDirectory(base_dir)
            self.ha_process.start("cmd.exe", ["/c", hass_cmd])
            self.ha_status.setText("● פעיל")
            self.ha_status.setObjectName("status_on")
            self.ha_status.setStyle(self.ha_status.style())

    def stop_ha(self):
        if self.ha_process and self.ha_process.state() != QProcess.ProcessState.NotRunning:
            pid = self.ha_process.processId()
            os.system(f"taskkill /f /t /pid {pid} >nul 2>&1")
            self.ha_process.kill()
            self.ha_process = None
        
        self.ha_status.setText("● כבוי")
        self.ha_status.setObjectName("status_off")
        self.ha_status.setStyle(self.ha_status.style())

    def start_cf(self):
        base_dir = self.get_hass_wp_dir()
        if not base_dir:
            return

        cloudflared_exe = os.path.join(base_dir, "cloudflared.exe")
        if not os.path.exists(cloudflared_exe):
            QMessageBox.critical(self, "שגיאה", f"לא נמצא קובץ cloudflared.exe בנתיב: {cloudflared_exe}")
            return

        if self.cf_process is None or self.cf_process.state() == QProcess.ProcessState.NotRunning:
            self.cf_process = QProcess(self)
            args = [
                "tunnel", "--protocol", "http2",
                "--url", "http://127.0.0.1:8123"
            ]
            if os.path.exists(NETFREE_CERT):
                args.extend(["--origin-ca-pool", NETFREE_CERT])

            self.cf_process.readyReadStandardError.connect(self.read_cf_output)
            self.cf_process.readyReadStandardOutput.connect(self.read_cf_output)
            self.cf_process.start(cloudflared_exe, args)

            self.cf_status.setText("● מתחבר...")
            self.cf_status.setObjectName("status_warning")
            self.cf_status.setStyle(self.cf_status.style())

    def read_cf_output(self):
        output = ""
        if self.cf_process:
            output += self.cf_process.readAllStandardError().data().decode("utf-8", errors="ignore")
            output += self.cf_process.readAllStandardOutput().data().decode("utf-8", errors="ignore")

        match = re.search(r"https://[a-zA-Z0-9-]+\.trycloudflare\.com", output)
        if match:
            new_url = match.group(0)
            if new_url != self.current_url:
                self.current_url = new_url
                self.url_input.setText(new_url)
                self.update_yemot_api(new_url)

    def force_update_yemot(self):
        url = self.url_input.text().strip()
        if not url:
            QMessageBox.warning(self, "שגיאה", "אין קישור פעיל לסנכרון. אנא ודא שמנהרת Cloudflare פעילה.")
            return
        
        self.update_yemot_api(url, show_popup=True)

    def _get_file_from_yemot(self, token, path):
        try:
            params = urllib.parse.urlencode({'token': token, 'path': path})
            api_url = f"https://www.call2all.co.il/ym/api/DownloadFile?{params}"
            req = urllib.request.Request(api_url)
            with urllib.request.urlopen(req, timeout=5) as response:
                if response.status == 200:
                    return response.read().decode('utf-8', errors='ignore')
        except Exception as e:
            print(f"שגיאה בהורדת קובץ {path}: {e}")
        return None

    def _update_ext_ini_link(self, token, path, new_url):
        """קורא את קובץ הגדרות השלוחה הקיים ומחליף אך ורק את חלק הדומיין"""
        original_content = self._get_file_from_yemot(token, path)
        if not original_content:
            return False
        
        if "api_link" in original_content:
            updated_content = re.sub(
                r"(api_link\s*=\s*)https?://[^/\r\n]+", 
                rf"\g<1>{new_url}", 
                original_content
            )
            return self._send_file_to_yemot(token, path, updated_content)
        return False

    def update_yemot_api(self, new_url, show_popup=False):
        sys_num = self.yemot_num_input.text().strip()
        password = self.yemot_pass_input.text().strip()
        extensions_raw = self.extensions_input.text().strip()

        if not sys_num or not password:
            self.cf_status.setText("● מחובר (חסרים פרטי ימות המשיח!)")
            self.cf_status.setObjectName("status_warning")
            self.cf_status.setStyle(self.cf_status.style())
            if show_popup:
                QMessageBox.warning(self, "שגיאה", "פרטי הגישה של ימות המשיח חסרים.")
            return

        token = f"{sys_num}:{password}"
        extensions = [ext.strip() for ext in extensions_raw.split(",") if ext.strip()]

        if not extensions:
            if show_popup:
                QMessageBox.warning(self, "שגיאה", "לא הוגדרו שלוחות לעדכון.")
            return

        updated_count = 0
        failed_extensions = []

        for ext in extensions:
            path = f"ivr2:{ext}/ext.ini"
            if self._update_ext_ini_link(token, path, new_url):
                updated_count += 1
            else:
                failed_extensions.append(ext)

        if updated_count == len(extensions):
            self.cf_status.setText(f"● מחובר + עודכנו {updated_count} שלוחות!")
            self.cf_status.setObjectName("status_on")
            if show_popup:
                QMessageBox.information(self, "סנכרון ידני", f"הסנכרון הושלם בהצלחה!\nעודכנו {updated_count} שלוחות.")
        elif updated_count > 0:
            self.cf_status.setText(f"● עודכנו חלקית ({updated_count}/{len(extensions)})")
            self.cf_status.setObjectName("status_warning")
            if show_popup:
                QMessageBox.warning(self, "שגיאה חלקית", f"עודכנו {updated_count} שלוחות.\nלא ניתן היה לעדכן את השלוחות הבאות: {', '.join(failed_extensions)}\n(ודא שהן קיימות ומוגדרות כסוג API במערכת ימות המשיח ומכילות הגדרת api_link).")
        else:
            self.cf_status.setText("● מחובר (שגיאה בעדכון השלוחות)")
            self.cf_status.setObjectName("status_warning")
            if show_popup:
                QMessageBox.critical(self, "שגיאה", "לא ניתן היה לעדכן אף שלוחה.\nודא שפרטי הגישה נכונים ושהשלוחות קיימות ומכילות הגדרת api_link.")

        self.cf_status.setStyle(self.cf_status.style())

    def _send_file_to_yemot(self, token, path, contents):
        try:
            api_url = "https://www.call2all.co.il/ym/api/UploadTextFile"
            data = urllib.parse.urlencode({
                'token': token,
                'what': path,
                'contents': contents
            }).encode('utf-8')
            req = urllib.request.Request(api_url, data=data)
            with urllib.request.urlopen(req, timeout=5) as response:
                return response.status == 200
        except Exception as e:
            print(f"שגיאה בהעלאת קובץ {path} לימות המשיח: {e}")
            return False

    def stop_cf(self):
        if self.cf_process and self.cf_process.state() != QProcess.ProcessState.NotRunning:
            pid = self.cf_process.processId()
            os.system(f"taskkill /f /t /pid {pid} >nul 2>&1")
            self.cf_process.kill()
            self.cf_process = None
        
        self.cf_status.setText("● כבוי")
        self.cf_status.setObjectName("status_off")
        self.cf_status.setStyle(self.cf_status.style())
        self.url_input.clear()
        self.current_url = ""

    def start_all(self):
        self.start_ha()
        self.start_cf()

    def stop_all(self):
        self.stop_ha()
        self.stop_cf()

    def is_startup_enabled(self):
        return os.path.exists(BAT_PATH)

    def toggle_startup(self, checked):
        if checked:
            try:
                script_path = os.path.abspath(sys.argv[0])
                if script_path.endswith(".exe"):
                    bat_content = f'@echo off\nstart "" "{script_path}" --autostart\n'
                else:
                    python_exe = sys.executable
                    bat_content = f'@echo off\nstart "" "{python_exe}" "{script_path}" --autostart\n'
                
                os.makedirs(STARTUP_DIR, exist_ok=True)
                with open(BAT_PATH, "w", encoding="utf-8") as f:
                    f.write(bat_content)
            except Exception as e:
                QMessageBox.warning(self, "שגיאה", f"לא ניתן להגדיר הפעלה אוטומטית: {e}")
                self.chk_startup.setChecked(False)
        else:
            try:
                if os.path.exists(BAT_PATH):
                    os.remove(BAT_PATH)
            except Exception as e:
                QMessageBox.warning(self, "שגיאה", f"לא ניתן להסיר הפעלה אוטומטית: {e}")
                self.chk_startup.setChecked(True)

    def closeEvent(self, event):
        self.stop_all()
        event.accept()

    def apply_styles(self):
        qss = """
        QMainWindow {
            background-color: #0f172a;
        }
        QLabel {
            color: #f8fafc;
        }
        #card {
            background-color: #1e293b;
            border-radius: 12px;
            border: 1px solid #334155;
            padding: 12px;
        }
        QPushButton {
            background-color: #3b82f6;
            color: white;
            border: none;
            border-radius: 8px;
            padding: 8px 16px;
            font-size: 13px;
            font-weight: bold;
        }
        QPushButton:hover {
            background-color: #2563eb;
        }
        #btn_danger {
            background-color: #ef4444;
        }
        #btn_danger:hover {
            background-color: #dc2626;
        }
        #btn_secondary {
            background-color: #475569;
        }
        #btn_secondary:hover {
            background-color: #334155;
        }
        #btn_success {
            background-color: #10b981;
        }
        #btn_success:hover {
            background-color: #059669;
        }
        QLineEdit {
            background-color: #0f172a;
            color: #38bdf8;
            border: 1px solid #334155;
            border-radius: 6px;
            padding: 8px;
            font-size: 12px;
        }
        QCheckBox {
            color: #e2e8f0;
            font-size: 13px;
            font-weight: bold;
            margin-top: 5px;
        }
        QCheckBox::indicator {
            width: 16px;
            height: 16px;
        }
        #status_off {
            color: #ef4444;
            font-weight: bold;
        }
        #status_on {
            color: #10b981;
            font-weight: bold;
        }
        #status_warning {
            color: #f59e0b;
            font-weight: bold;
        }
        """
        self.setStyleSheet(qss)

if __name__ == "__main__":
    app = QApplication(sys.argv)
    window = SmartHomeControlPanel()
    window.show()
    sys.exit(app.exec())