from __future__ import annotations

import os
from pathlib import Path
import sys
import time
import ctypes
import threading
import traceback
import webbrowser

if __package__:
    from .bridge import HydrologyBridgeApi
else:
    sys.path.insert(0, str(Path(__file__).resolve().parents[1]))
    from hydrology_app.bridge import HydrologyBridgeApi


APP_DIR = Path(__file__).resolve().parent
ROOT_DIR = APP_DIR.parent
WEBUI_INDEX = APP_DIR / "webui" / "index.html"
UI_LOG_FILE = ROOT_DIR / ".launcher" / "ui_engine.log"
WEBVIEW_PROFILE_DIR = ROOT_DIR / ".launcher" / "webview_profile"
FALLBACK_EXIT_CODE = 12
MISSING_WEBVIEW2_EXIT_CODE = 13
RELOGIN_EXIT_CODE = 14
WEBVIEW2_DOWNLOAD_URL = "https://developer.microsoft.com/microsoft-edge/webview2/"
WEBVIEW2_SAFE_ARGUMENTS = "--disable-gpu --disable-gpu-compositing"


def _log_ui(message: str) -> None:
    try:
        UI_LOG_FILE.parent.mkdir(parents=True, exist_ok=True)
        timestamp = time.strftime("%Y-%m-%d %H:%M:%S")
        UI_LOG_FILE.open("a", encoding="utf-8").write(f"[{timestamp}] {message}\n")
    except OSError:
        pass


def _program_files_webview_exists() -> bool:
    candidates = []
    for env_name in ("PROGRAMFILES(X86)", "PROGRAMFILES", "LOCALAPPDATA"):
        root = os.environ.get(env_name)
        if root:
            candidates.append(Path(root) / "Microsoft" / "EdgeWebView" / "Application")
    return any(path.exists() and any(path.glob("*/msedgewebview2.exe")) for path in candidates)


def _registry_webview_exists() -> bool:
    if os.name != "nt":
        return True
    try:
        import winreg
    except ImportError:
        return False

    roots = [
        (winreg.HKEY_CURRENT_USER, r"SOFTWARE\Microsoft\EdgeUpdate\Clients"),
        (winreg.HKEY_LOCAL_MACHINE, r"SOFTWARE\Microsoft\EdgeUpdate\Clients"),
        (winreg.HKEY_LOCAL_MACHINE, r"SOFTWARE\WOW6432Node\Microsoft\EdgeUpdate\Clients"),
    ]
    for hive, key_path in roots:
        try:
            with winreg.OpenKey(hive, key_path) as clients:
                index = 0
                while True:
                    try:
                        subkey_name = winreg.EnumKey(clients, index)
                    except OSError:
                        break
                    index += 1
                    try:
                        with winreg.OpenKey(clients, subkey_name) as subkey:
                            name = str(winreg.QueryValueEx(subkey, "name")[0])
                            version = str(winreg.QueryValueEx(subkey, "pv")[0])
                    except OSError:
                        continue
                    if "webview2" in name.lower() and version:
                        return True
        except OSError:
            continue
    return False


def has_webview2_runtime() -> bool:
    if os.environ.get("HYDROLOGY_FORCE_TKINTER_FALLBACK") == "1":
        _log_ui("WebView2 is forced to missing for diagnostics; legacy tkinter fallback is disabled")
        return False
    if os.name != "nt":
        return True
    detected = _registry_webview_exists() or _program_files_webview_exists()
    _log_ui(f"WebView2 runtime detected={detected}")
    return detected


def _enable_dpi_awareness() -> None:
    """Make pywebview text and SVG lines render sharply on Windows scaled displays."""
    if os.name != "nt":
        return
    try:
        ctypes.windll.shcore.SetProcessDpiAwareness(1)
        _log_ui("DPI awareness set through shcore.SetProcessDpiAwareness(1)")
        return
    except Exception as exc:  # noqa: BLE001
        _log_ui(f"SetProcessDpiAwareness failed: {exc}")
    try:
        ctypes.windll.user32.SetProcessDPIAware()
        _log_ui("DPI awareness set through user32.SetProcessDPIAware()")
    except Exception as exc:  # noqa: BLE001
        _log_ui(f"SetProcessDPIAware fallback failed: {exc}")


def _configure_webview_environment() -> None:
    """Use a stable WebView2 profile and disable GPU compositing on machines that black-screen."""
    try:
        WEBVIEW_PROFILE_DIR.mkdir(parents=True, exist_ok=True)
    except OSError as exc:
        _log_ui(f"Creating WebView profile directory failed: {exc}")
    existing_args = os.environ.get("WEBVIEW2_ADDITIONAL_BROWSER_ARGUMENTS", "").strip()
    if WEBVIEW2_SAFE_ARGUMENTS not in existing_args:
        combined = f"{existing_args} {WEBVIEW2_SAFE_ARGUMENTS}".strip()
        os.environ["WEBVIEW2_ADDITIONAL_BROWSER_ARGUMENTS"] = combined
        _log_ui(f"WEBVIEW2_ADDITIONAL_BROWSER_ARGUMENTS={combined}")


def _show_startup_error_message(title: str, message: str) -> None:
    _log_ui(f"{title}: {message}")
    if os.name == "nt":
        try:
            import ctypes

            ctypes.windll.user32.MessageBoxW(None, message, title, 0x00000010)
            return
        except Exception as exc:  # noqa: BLE001
            _log_ui(f"Native startup error message failed: {exc}")
    try:
        import tkinter as tk
        from tkinter import messagebox

        root = tk.Tk()
        root.withdraw()
        messagebox.showerror(title, message)
        root.destroy()
    except Exception as exc:  # noqa: BLE001
        _log_ui(f"Startup error message failed: {exc}")


def _show_webview2_missing_message() -> None:
    """Tell users why the HTML interface cannot open instead of silently showing a different UI."""
    _log_ui("Showing WebView2 Runtime missing message")
    message = (
        "当前电脑缺少 Microsoft Edge WebView2 Runtime，无法打开新版 HTML 界面。\n\n"
        "这是部分电脑打不开、黑屏或界面不一致的常见根因。软件已禁止退回旧界面，"
        "请安装 WebView2 Runtime 后重新打开软件。"
    )
    if os.name == "nt":
        try:
            import ctypes

            ctypes.windll.user32.MessageBoxW(None, message, "慧通智达水文计算云平台", 0x00000030)
        except Exception as exc:  # noqa: BLE001
            _log_ui(f"Native WebView2 missing message failed: {exc}")
            print(message)
    else:
        print(message)
    try:
        webbrowser.open(WEBVIEW2_DOWNLOAD_URL)
    except Exception as exc:  # noqa: BLE001
        _log_ui(f"Opening WebView2 download page failed: {exc}")


def main() -> int:
    # @hook UI58-DPI 20260804
    # Enable Windows DPI awareness before creating the pywebview window to keep text and SVG lines crisp.
    _enable_dpi_awareness()
    # @hook WEBVIEW-black-screen 20260806
    # Use a persistent WebView2 profile and conservative rendering flags so older GPUs do not show a black window.
    _configure_webview_environment()
    if not WEBUI_INDEX.exists():
        _log_ui(f"webui index not found: {WEBUI_INDEX}")
        _show_startup_error_message(
            "慧通智达水文计算云平台",
            f"界面文件缺失，软件包可能下载不完整：\n{WEBUI_INDEX}\n\n请重新打开软件触发自动更新，或重新下载完整安装包。",
        )
        return 2
    if not has_webview2_runtime():
        _log_ui("HTML UI skipped because WebView2 Runtime is missing")
        _show_webview2_missing_message()
        return MISSING_WEBVIEW2_EXIT_CODE
    try:
        import webview
    except Exception as exc:  # noqa: BLE001
        _log_ui(f"pywebview import failed: {exc}")
        return FALLBACK_EXIT_CODE

    restart_login_requested = {"value": False}

    def request_login_restart() -> None:
        restart_login_requested["value"] = True

        def close_window() -> None:
            try:
                import webview

                for window in list(webview.windows):
                    window.destroy()
            except Exception as exc:  # noqa: BLE001
                _log_ui(f"login restart window close failed: {exc}")

        threading.Timer(0.25, close_window).start()

    api = HydrologyBridgeApi(request_login_restart=request_login_restart)
    # @hook UI1 20260804
    # Loads the local HTML dashboard through pywebview as the UI-1 entry point.
    # @hook UI4 20260804
    # HTML UI startup checks WebView2 and fails visibly instead of opening the legacy tkinter workspace.
    _log_ui(f"Starting HTML UI from {WEBUI_INDEX}; profile={WEBVIEW_PROFILE_DIR}")
    try:
        webview.settings["ALLOW_DOWNLOADS"] = True
        webview.create_window(
            "慧通智达水文计算云平台",
            WEBUI_INDEX.as_uri(),
            js_api=api,
            width=1280,
            height=900,
            min_size=(960, 720),
            resizable=True,
            background_color="#f5f7fa",
        )
        webview.start(debug=False, private_mode=False, storage_path=str(WEBVIEW_PROFILE_DIR))
    except Exception as exc:  # noqa: BLE001
        _log_ui("HTML UI startup failed:\n" + traceback.format_exc())
        _show_startup_error_message(
            "慧通智达水文计算云平台",
            "当前电脑的 HTML 界面启动失败。\n\n"
            "常见原因是 WebView2 运行时损坏、显卡驱动兼容问题，或软件包更新不完整。\n"
            f"错误信息：{exc}\n\n"
            f"诊断日志：{UI_LOG_FILE}",
        )
        return FALLBACK_EXIT_CODE
    if restart_login_requested["value"]:
        _log_ui("HTML UI requested logout; returning relogin exit code for login flow")
        return RELOGIN_EXIT_CODE
    _log_ui("HTML UI closed normally")
    return 0


if __name__ == "__main__":
    raise SystemExit(main())
