"""
Quan ly vong doi Chrome.

LOGIN MODE   : Mo Chrome binh thuong bang subprocess (khong co Playwright).
AUTOMATE MODE: Mo Chrome bang subprocess voi --remote-debugging-port,
               sau do Playwright ket noi qua CDP.
=> Khong co banner "controlled by automated software".
"""
from __future__ import annotations

import socket
import subprocess
import sys
import time
from pathlib import Path

from .constants import (
    CHROME_BINARY,
    CDP_PORT_BASE,
    CHROME_LAUNCH_TIMEOUT_SEC,
    BROWSER_SLOW_MO,
    SORA_URL,
    is_sora_page_url,
)


# ---------------------------------------------------------------------------
# Internal helpers
# ---------------------------------------------------------------------------

def _macos_get_frontmost_app() -> str | None:
    """Lay ten app dang focus (macOS). De sau do keo focus ve lai."""
    if sys.platform != "darwin":
        return None
    try:
        out = subprocess.run(
            ["osascript", "-e", 'tell application "System Events" to get name of first process whose frontmost is true'],
            capture_output=True,
            text=True,
            timeout=2,
        )
        if out.returncode == 0 and out.stdout:
            return out.stdout.strip()
    except Exception:
        pass
    return None


def _macos_activate_app(app_name: str) -> None:
    """Keo focus ve app (macOS). Tranh Chrome che mat Cursor/IDE."""
    if sys.platform != "darwin" or not app_name:
        return
    try:
        subprocess.run(
            ["osascript", "-e", f'tell application "{app_name}" to activate'],
            capture_output=True,
            timeout=2,
        )
    except Exception:
        pass


def _wait_for_cdp(port: int, proc: subprocess.Popen, timeout: float = 30.0) -> None:
    """Block cho den khi Chrome mo cong CDP, kiem tra process con song."""
    deadline = time.time() + timeout
    while time.time() < deadline:
        # Neu Chrome thoat som thi bao loi ngay
        ret = proc.poll()
        if ret is not None:
            stderr_out = ""
            if proc.stderr:
                stderr_out = proc.stderr.read().decode(errors="replace")[:500]
            raise RuntimeError(
                f"Chrome thoat ngay lap tuc (exit code {ret}).\n"
                f"Stderr: {stderr_out or '(trong)'}"
            )
        try:
            with socket.create_connection(("127.0.0.1", port), timeout=1):
                return
        except OSError:
            time.sleep(0.4)
    # Het timeout — lay stderr de debug
    stderr_out = ""
    if proc.stderr:
        stderr_out = proc.stderr.read().decode(errors="replace")[:500]
    raise TimeoutError(
        f"Chrome khong mo cong CDP {port} sau {timeout}s.\n"
        f"Stderr: {stderr_out or '(trong)'}\n"
        "Thu tat tat ca Chrome dang mo roi chay lai."
    )


def _spawn_chrome(
    profile_path: Path,
    *,
    debug_port: int | None = None,
    url: str | None = None,
    start_minimized: bool = False,
) -> subprocess.Popen:
    cmd = [
        CHROME_BINARY,
        f"--user-data-dir={profile_path}",
        "--no-first-run",
        "--no-default-browser-check",
        "--mute-audio",
        "--disable-features=OptimizationGuideModelDownloading",
    ]
    if debug_port:
        cmd.append(f"--remote-debugging-port={debug_port}")
    if start_minimized:
        cmd.append("--start-minimized")  # Khong keo focus, tranh lam phien user dang lam viec
    if url:
        cmd.append(url)
    print(f"  [chrome] CMD: {' '.join(cmd[:4])} ...")
    return subprocess.Popen(
        cmd,
        stdout=subprocess.DEVNULL,
        stderr=subprocess.PIPE,  # capture de debug
    )


# ---------------------------------------------------------------------------
# Login mode
# ---------------------------------------------------------------------------

def launch_chrome_for_login(profile_path: Path, url: str | None = None) -> subprocess.Popen:
    """Mo mot cua so Chrome thong thuong de user dang nhap thu cong."""
    print(f"  [chrome] Mo profile: {profile_path.name} ...")
    return _spawn_chrome(profile_path, url=url)


# ---------------------------------------------------------------------------
# Automate mode
# ---------------------------------------------------------------------------

def _remove_singleton_lock(profile_path: Path) -> None:
    """Xoa file khoa con lai neu Chrome bi tat dot ngot lan truoc."""
    lock = profile_path / "SingletonLock"
    if lock.exists():
        lock.unlink()
        print(f"  [chrome] Da xoa SingletonLock cu: {lock}")


def launch_chrome_for_automation(
    profile_path: Path,
    debug_port: int,
    timeout: float = 30.0,
) -> tuple:
    """
    Mo Chrome voi cong CDP va ket noi Playwright qua CDP.
    Tra ve (proc, playwright, browser, context, page).
    Caller phai goi pw.stop() va close_chrome(proc) khi xong.
    """
    from playwright.sync_api import sync_playwright

    profile_name = profile_path.name
    _remove_singleton_lock(profile_path)

    # Truoc khi mo Chrome, nho app dang focus de keo focus ve lai (macOS)
    _frontmost_before = _macos_get_frontmost_app()

    print(f"  [chrome] Khoi dong: {profile_name} (port {debug_port}) ...")
    proc = _spawn_chrome(
        profile_path,
        debug_port=debug_port,
        url=SORA_URL,
        start_minimized=True,
    )

    print(f"  [chrome] Cho CDP san sang (port {debug_port}) ...")
    _wait_for_cdp(debug_port, proc=proc, timeout=timeout)

    print(f"  [chrome] Ket noi Playwright ...")
    pw = sync_playwright().start()
    browser = pw.chromium.connect_over_cdp(
        f"http://127.0.0.1:{debug_port}",
        slow_mo=BROWSER_SLOW_MO,
    )
    context = browser.contexts[0] if browser.contexts else browser.new_context()

    # Cho Chrome load xong cac tab session cu + tab Sora moi mo
    time.sleep(2)

    # Tim tab dang o Sora (sora.com hoac sora.chatgpt.com); neu khong co thi navigate tab dau tien den do
    page = next(
        (p for p in context.pages if is_sora_page_url(p.url)),
        None,
    )
    if page is None:
        page = context.pages[0] if context.pages else context.new_page()
        print(f"  [chrome] Khong tim thay tab Sora, navigate den {SORA_URL} ...")
        page.goto(SORA_URL, wait_until="domcontentloaded", timeout=30_000)

    # Khong goi bring_to_front() de tranh keo cua so Chrome len truoc
    if not is_sora_page_url(page.url):
        page.goto(SORA_URL, wait_until="domcontentloaded", timeout=30_000)

    # Keo focus ve lai app user dang dung (Cursor, Terminal, ...) de Chrome khong che
    if _frontmost_before:
        time.sleep(0.5)
        _macos_activate_app(_frontmost_before)

    print(f"  [chrome] San sang: {profile_name} (tab: {page.url[:60]})")
    return proc, pw, browser, context, page


def close_chrome(proc: subprocess.Popen) -> None:
    """Tat Chrome mot cach an toan."""
    proc.terminate()
    try:
        proc.wait(timeout=5)
    except subprocess.TimeoutExpired:
        proc.kill()
