"""
cef_browser.py v2 — Embedded Chromium INSIDE Kivy's SDL2 window

v1 created a separate Win32 window (same as external Chrome).
v2 creates CEF as a **child window** of Kivy's SDL_app window:
  - No separate taskbar entry
  - No z-order fighting
  - No desktop flash
  - CEF message loop pumped via Kivy Clock (main thread)
"""

import ctypes
import os
from pathlib import Path

try:
    from cefpython3 import cefpython as cef
    CEF_AVAILABLE = True
except ImportError:
    CEF_AVAILABLE = False

WS_CHILD = 0x40000000
WS_VISIBLE = 0x10000000
WS_CLIPSIBLINGS = 0x04000000
WS_CLIPCHILDREN = 0x02000000
SW_HIDE = 0
SW_SHOWNORMAL = 1


class CefBrowser:
    def __init__(self):
        self._browser = None
        self._cef_initialized = False
        self._child_hwnd = None
        self._kivy_hwnd = None
        self._clock_event = None
        self._showing = False

    # ── Public API ──────────────────────────────────────────────────

    def show(self, url):
        if not CEF_AVAILABLE:
            return False
        if not self._cef_initialized:
            self._init_cef()
        if self._browser is not None:
            self._browser.Navigate(url)
            self._show_in_kivy()
            return True
        return self._create_embedded(url)

    def hide(self):
        self._showing = False
        if self._clock_event is not None:
            try:
                from kivy.clock import Clock
                Clock.unschedule(self._clock_event)
            except Exception:
                pass
            self._clock_event = None
        if self._child_hwnd:
            try:
                ctypes.windll.user32.ShowWindow(self._child_hwnd, SW_HIDE)
            except Exception:
                pass
        if self._browser is not None:
            try:
                self._browser.CloseBrowser(True)
            except Exception:
                pass
            self._browser = None
        if self._child_hwnd:
            try:
                ctypes.windll.user32.DestroyWindow(self._child_hwnd)
            except Exception:
                pass
            self._child_hwnd = None

    def shutdown(self):
        self.hide()
        if self._cef_initialized:
            try:
                cef.Shutdown()
            except Exception:
                pass
            self._cef_initialized = False

    def navigate(self, url):
        if self._browser is not None:
            self._browser.Navigate(url)

    def is_showing(self):
        return self._showing

    def resize(self, width, height):
        """Called when Kivy window resizes — repositions CEF child."""
        if self._child_hwnd:
            ctypes.windll.user32.SetWindowPos(
                self._child_hwnd, 0, 0, 0, width, height, 0x0004
            )
            if self._browser:
                self._browser.SetBounds(0, 0, width, height)

    # ── Internal ────────────────────────────────────────────────────

    def _init_cef(self):
        settings = {
            "multi_threaded_message_loop": False,
            "single_process": True,
            "log_severity": cef.LOGSEVERITY_WARNING,
            "user_agent": "Mozilla/5.0 KiwySignage/1.0",
            "cache_path": str(
                Path(os.environ.get("KIWY_DATA_DIR", ".")) / ".cef_cache"
            ),
        }
        cef.Initialize(settings=settings)
        self._cef_initialized = True

    def _get_kivy_hwnd(self):
        if self._kivy_hwnd is not None:
            return self._kivy_hwnd
        try:
            import win32gui
            hwnd = win32gui.FindWindow("SDL_app", None)
            if hwnd:
                self._kivy_hwnd = hwnd
                return hwnd
        except Exception:
            pass
        return None

    def _create_embedded(self, url):
        kivy_hwnd = self._get_kivy_hwnd()
        if not kivy_hwnd:
            return False

        user32 = ctypes.windll.user32
        rect = (ctypes.c_long * 4)()
        user32.GetClientRect(kivy_hwnd, ctypes.byref(rect))
        w, h = rect[2], rect[3]

        hinstance = ctypes.windll.kernel32.GetModuleHandleW(None)
        self._child_hwnd = user32.CreateWindowExW(
            0, b'#32770', b'',
            WS_CHILD | WS_CLIPSIBLINGS | WS_CLIPCHILDREN,
            0, 0, w, h, kivy_hwnd, 0, hinstance, 0,
        )
        if not self._child_hwnd:
            return False

        winfo = cef.WindowInfo()
        winfo.SetAsChild(self._child_hwnd, [0, 0, w, h])
        self._browser = cef.CreateBrowserSync(
            window_info=winfo,
            settings={"background_color": 0x00000000},
            url=url,
        )
        self._showing = True
        self._show_in_kivy()
        self._start_clock_pump()
        return True

    def _show_in_kivy(self):
        if not self._child_hwnd:
            return
        kivy_hwnd = self._get_kivy_hwnd()
        if kivy_hwnd:
            user32 = ctypes.windll.user32
            rect = (ctypes.c_long * 4)()
            user32.GetClientRect(kivy_hwnd, ctypes.byref(rect))
            user32.SetWindowPos(
                self._child_hwnd, 0, 0, 0, rect[2], rect[3], 0x0004
            )
        ctypes.windll.user32.ShowWindow(self._child_hwnd, SW_SHOWNORMAL)
        self._showing = True

    def _start_clock_pump(self):
        if self._clock_event is not None:
            return

        def _pump(dt):
            if self._cef_initialized:
                try:
                    cef.MessageLoopWork()
                except Exception:
                    pass
            if self._showing:
                from kivy.clock import Clock
                self._clock_event = Clock.schedule_once(_pump, 0.01)

        from kivy.clock import Clock
        self._clock_event = Clock.schedule_once(_pump, 0)
