"""
Logic tu dong hoa Sora.

Flow cho moi san pham:
  1. reset_page(page)          — tai lai Sora de xoa trang thai cu
  2. fill_prompt(page, text)   — dien textarea
  3. upload_image(page, src)   — inject anh (local path hoac URL)
  4. click_create(page)        — click nut Tao video
"""
from __future__ import annotations

import base64
import tempfile
import time
from pathlib import Path

from playwright.sync_api import Page

from .constants import (
    SORA_URL,
    is_sora_page_url,
    SEL_TEXTAREA,
    SEL_FILE_INPUT,
    SEL_CREATE_BTN,
    DEFAULT_IMAGE_PATH,
)


def _log(prefix: str, msg: str) -> None:
    """In log kem prefix profile de de debug khi chay nhieu profile."""
    if prefix:
        print(f"  [{prefix}] [sora] {msg}")
    else:
        print(f"  [sora] {msg}")


# ---------------------------------------------------------------------------
# Navigation
# ---------------------------------------------------------------------------

def _ensure_sora_page(page: Page, profile_alias: str = "") -> None:
    """Dam bao tab dung trang Sora. Chi goto neu URL khong phai Sora. Khong bring_to_front de tranh keo focus."""
    if not is_sora_page_url(page.url):
        _log(profile_alias, "Tab khong phai Sora, goto Sora ...")
        page.goto(SORA_URL, wait_until="domcontentloaded", timeout=30_000)


def open_sora(page: Page, timeout: int = 30_000, profile_alias: str = "") -> None:
    """Dieu huong den Sora va cho textarea hien ra."""
    _log(profile_alias, f"Mo trang {SORA_URL} ...")
    page.goto(SORA_URL, wait_until="domcontentloaded", timeout=timeout)
    page.wait_for_selector(SEL_TEXTAREA, timeout=timeout)
    _log(profile_alias, "Trang san sang.")


def reset_page(page: Page, profile_alias: str = "") -> None:
    """Tai lai Sora de xoa noi dung cu truoc khi xu ly san pham tiep theo."""
    _log(profile_alias, "Tai lai trang ...")
    page.reload(wait_until="domcontentloaded", timeout=30_000)
    page.wait_for_selector(SEL_TEXTAREA, timeout=20_000)
    time.sleep(1)
    _ensure_sora_page(page, profile_alias)
    _log(profile_alias, "Trang da duoc reset.")


# ---------------------------------------------------------------------------
# Fill prompt
# ---------------------------------------------------------------------------

def fill_prompt(page: Page, text: str, profile_alias: str = "") -> None:
    """Tim textarea va dien noi dung prompt."""
    short = text[:60] + "..." if len(text) > 60 else text
    _log(profile_alias, f"Dien prompt: {short!r}")

    textarea = page.locator(SEL_TEXTAREA)
    textarea.wait_for(state="visible", timeout=15_000)
    textarea.click()
    textarea.fill("")
    textarea.fill(text)

    actual = textarea.input_value()
    if actual != text:
        raise RuntimeError(
            f"Dien prompt that bai. Gia tri hien tai: {actual[:40]!r}"
        )
    _log(profile_alias, "Prompt da dien xong.")


# ---------------------------------------------------------------------------
# Image upload
# ---------------------------------------------------------------------------

def _download_via_browser(page: Page, url: str, profile_alias: str = "") -> Path:
    """Tai anh bang fetch cua browser (bo qua bot detection cua server)."""
    _log(profile_alias, f"Tai anh qua browser: {url[:70]} ...")
    suffix = Path(url.split("?")[0]).suffix or ".jpg"

    b64: str = page.evaluate(
        """async (url) => {
            const r = await fetch(url);
            if (!r.ok) throw new Error(`HTTP ${r.status}`);
            const blob = await r.blob();
            return new Promise(resolve => {
                const reader = new FileReader();
                reader.onloadend = () => resolve(reader.result.split(',')[1]);
                reader.readAsDataURL(blob);
            });
        }""",
        url,
    )

    tmp = tempfile.NamedTemporaryFile(delete=False, suffix=suffix)
    tmp.write(base64.b64decode(b64))
    tmp.close()
    path = Path(tmp.name)
    _log(profile_alias, f"Anh da tai: {path.stat().st_size} bytes")
    return path


def upload_image(page: Page, image_source: str | Path, profile_alias: str = "") -> None:
    """
    Upload anh len Sora tu local path hoac URL.
    Neu la URL, tai ve qua browser truoc.
    """
    src = str(image_source)
    cleanup = False

    if src.startswith("http://") or src.startswith("https://"):
        local_path = _download_via_browser(page, src, profile_alias)
        cleanup = True
    else:
        local_path = Path(src)

    if not local_path.exists():
        raise FileNotFoundError(f"Khong tim thay file anh: {local_path}")

    _log(profile_alias, f"Upload anh: {local_path.name} ({local_path.stat().st_size} bytes)")
    file_input = page.locator(SEL_FILE_INPUT).first
    file_input.set_input_files(str(local_path))

    # Xu ly modal xin quyen "Animating photos with real people"
    try:
        continue_btn = page.get_by_role("button", name="Continue")
        continue_btn.wait_for(state="visible", timeout=3_000)
        continue_btn.click()
        _log(profile_alias, "Da click Continue tren modal xin quyen.")
        time.sleep(0.5)
    except Exception:
        pass  # Modal khong xuat hien, tiep tuc binh thuong

    _log(profile_alias, "Anh da upload xong.")

    if cleanup:
        local_path.unlink(missing_ok=True)


# ---------------------------------------------------------------------------
# Configure settings (duration + video count)
# ---------------------------------------------------------------------------

def _open_settings(page: Page, timeout: int, profile_alias: str = "") -> None:
    """
    Click nut Settings va verify menu thuc su mo ra.
    Retry toi da 5 lan de tranh truong hop click khong an.
    """
    btn = page.get_by_role("button", name="Settings").nth(1)
    for attempt in range(1, 6):
        btn.wait_for(state="visible", timeout=timeout)
        btn.scroll_into_view_if_needed()
        btn.click()
        # Cho menu xuat hien (co menuitem la mo thanh cong)
        try:
            page.get_by_role("menuitem").first.wait_for(state="visible", timeout=4_000)
            return
        except Exception:
            _log(profile_alias, f"Settings chua mo (lan {attempt}/5), thu lai ...")
            time.sleep(0.5)
    raise RuntimeError("Khong mo duoc Settings menu sau 5 lan thu.")


def configure_settings(page: Page, timeout: int = 20_000, profile_alias: str = "") -> None:
    """
    Cau hinh Settings popup:
      - Duration : 15 seconds  (Settings -> Duration -> 15 seconds)
      - Videos   : 3 videos    (Settings -> Videos   -> 3 videos)
    Neu khong tim duoc: cho 15s roi thu lai (khong F5 de tranh mat prompt/anh), toi da 1 phut.
    """
    _WAIT_RETRY_SEC = 15
    _MAX_TOTAL_SEC = 60
    deadline = time.time() + _MAX_TOTAL_SEC
    last_error: Exception | None = None

    while time.time() < deadline:
        try:
            _ensure_sora_page(page, profile_alias)
            time.sleep(0.3)
            page.evaluate("window.scrollTo(0, 0)")
            time.sleep(0.2)
            # ── Lan 1: chon Duration = 15 seconds ─────────────────────────
            _log(profile_alias, "Settings: chon Duration ...")
            _open_settings(page, timeout, profile_alias)

            duration_menu = page.get_by_role("menuitem").filter(has_text="Duration").first
            duration_menu.wait_for(state="visible", timeout=timeout)
            duration_menu.scroll_into_view_if_needed()
            duration_menu.click()
            time.sleep(0.5)

            opt_15s = page.get_by_role("menuitemradio").filter(has_text="15 seconds").first
            opt_15s.wait_for(state="visible", timeout=timeout)
            opt_15s.scroll_into_view_if_needed()
            opt_15s.click()
            time.sleep(0.5)
            _log(profile_alias, "Da chon 15 seconds.")

            # ── Lan 2: chon Videos = 3 videos ─────────────────────────────
            _log(profile_alias, "Settings: chon Videos ...")
            _open_settings(page, timeout, profile_alias)

            videos_menu = page.get_by_role("menuitem").filter(has_text="Videos").first
            videos_menu.wait_for(state="visible", timeout=timeout)
            videos_menu.scroll_into_view_if_needed()
            videos_menu.click()
            time.sleep(2)

            opt_3v = page.get_by_role("menuitemradio").filter(has_text="3 videos").first
            opt_3v.wait_for(state="visible", timeout=timeout)
            opt_3v.scroll_into_view_if_needed()
            opt_3v.click()
            time.sleep(0.5)
            _log(profile_alias, "Da chon 3 videos.")
            return
        except Exception as e:
            last_error = e
            if time.time() >= deadline:
                raise
            _log(
                profile_alias,
                f"Khong tim thay Settings/3 videos ({e!r}), cho {_WAIT_RETRY_SEC}s roi thu lai (khong F5 de giu prompt/anh) ...",
            )
            time.sleep(_WAIT_RETRY_SEC)
            if time.time() >= deadline:
                raise last_error
            # Khong reload trang — se mat prompt va anh da dien. Chi bring_to_front + scroll roi thu lai.

    if last_error is not None:
        raise last_error
    raise RuntimeError("Khong cau hinh duoc Settings trong 1 phut.")


# ---------------------------------------------------------------------------
# Click create
# ---------------------------------------------------------------------------


class VideoGenLimitReachedError(RuntimeError):
    """Profile da dat gioi han tao video trong ngay (tooltip 'out of video gens')."""


def click_create(page: Page, timeout: int = 10_000, profile_alias: str = "") -> None:
    """Click nut 'Create video'."""
    _log(profile_alias, "Tim nut Tao video ...")

    btn = page.locator(SEL_CREATE_BTN)
    count = btn.count()

    if count == 0:
        raise RuntimeError(
            "Khong tim thay nut Tao video. "
            "Kiem tra lai dang nhap hoac trang thai trang Sora."
        )

    btn.wait_for(state="visible", timeout=timeout)

    if btn.get_attribute("data-disabled") == "true":
        raise RuntimeError(
            "Nut Tao video dang bi vo hieu hoa. "
            "Co the chua dien prompt hoac chua upload anh."
        )

    _RETRY_WAIT_SEC = 300  # 5 phut
    _MAX_RETRIES = 6       # toi da 6 lan (30 phut)

    for attempt in range(1, _MAX_RETRIES + 1):
        btn.click()

        # Cho 2 giay roi kiem tra tooltip
        time.sleep(2)
        # Gioi han tao video trong ngay — khong retry, raise de CLI dong profile va doi profile khac
        daily_limit_tooltip = page.locator("text=out of video gens")
        if daily_limit_tooltip.count() > 0:
            raise VideoGenLimitReachedError(
                "Profile da tao toi da video trong ngay (Sora bao 'out of video gens')."
            )
        job_limit_tooltip = page.locator("text=Only 3 jobs can run at a time")
        if job_limit_tooltip.count() == 0:
            _log(profile_alias, "Da click Tao video.")
            return

        mins = _RETRY_WAIT_SEC // 60
        _log(profile_alias, f"[lan {attempt}/{_MAX_RETRIES}] Dang co 3 jobs chay — cho {mins} phut roi thu lai ...")
        time.sleep(_RETRY_WAIT_SEC)

    raise RuntimeError("Da thu lai nhieu lan nhung Sora van bao 'Only 3 jobs can run at a time'.")


# ---------------------------------------------------------------------------
# Orchestration
# ---------------------------------------------------------------------------

def create_video(
    page: Page,
    prompt: str,
    image_source: str | Path | None = None,
    profile_alias: str = "",
) -> None:
    """
    Quy trinh day du: dien prompt -> upload anh -> click tao.
    image_source co the la local path, URL, hoac None (dung anh mac dinh).
    profile_alias: prefix trong log de de debug khi chay nhieu profile.
    """
    if image_source is None:
        image_source = DEFAULT_IMAGE_PATH

    _log(profile_alias, "=== BAT DAU TAO VIDEO ===")
    _log(profile_alias, f"Prompt : {prompt[:80]!r}")
    _log(profile_alias, f"Anh    : {str(image_source)[:80]}")

    _ensure_sora_page(page, profile_alias)
    fill_prompt(page, prompt, profile_alias)
    upload_image(page, image_source, profile_alias)
    configure_settings(page, profile_alias=profile_alias)
    # Dong Settings menu bang Escape truoc khi tim nut submit
    page.keyboard.press("Escape")
    time.sleep(0.3)
    click_create(page, profile_alias=profile_alias)

    _log(profile_alias, "=== HOAN THANH ===")
