"""S-CANVAS 인트로 로딩 스플래시.

Design/logo_intro.mp4 를 frameless Toplevel 중앙에 재생한 뒤 자동 종료.
메인 앱(`scanvas_maker.SCanvasApp`) 기동 직전에 호출한다.

기술 스택:
    - cv2 (VideoCapture) : MP4 프레임 디코드 (harness/quality_validator 가
      이미 의존하는 프로젝트 공통 dep).
    - PIL + tkinter.PhotoImage : 프레임 렌더.
    - tk.Tk + attributes("-alpha", ...) : frameless + 페이드 인/아웃 효과.

dynamic effects(사용자 요구 "역동적으로"):
    1. 시작 시 알파 0 → 1 페이드인 (400ms)
    2. 비디오 자체 애니메이션(logo_intro.mp4 는 고유 모션 포함)
    3. 종료 전 알파 1 → 0 페이드아웃 (400ms)
    4. 비디오 하단에 브랜드 tagline bar (오렌지 italic)
    5. max_duration_s 초과 시 강제 종료(safety)

실패 조건(조용히 skip):
    - logo_intro.mp4 없음
    - cv2/PIL import 실패
    - VideoCapture.open 실패
    메인 앱 기동은 항상 보장된다.
"""
from __future__ import annotations

import time
import tkinter as tk
from pathlib import Path
import contextlib


def show_intro_splash(
    video_path,
    max_duration_s: float = 12.0,
    fade_ms: int = 400,
    tagline: str = "S-CANVAS — Generative Design & Visualization Engine",
    max_display_w: int = 1000,
) -> None:
    """video_path 의 MP4 를 스플래시로 재생 후 블로킹 반환.

    Args:
        video_path: Path-like, .mp4 파일.
        max_duration_s: 비디오가 이 시간을 넘기면 강제 종료.
        fade_ms: 페이드인/아웃 각 구간 길이(ms).
        tagline: 비디오 아래에 표시할 문구.
        max_display_w: 화면상 최대 가로(px). 이보다 크면 aspect 유지 축소.

    동작:
        - 임시 tk.Tk 루트를 만들고 mainloop → 종료 시 완전 destroy.
        - 이후 `SCanvasApp()` 이 새 ctk.CTk 인스턴스를 만들어도 충돌 없음
          (Tk 루트가 이미 파괴됐으므로).
    """
    try:
        import cv2
        from PIL import Image, ImageTk
    except ImportError as e:
        print(f"[Intro] cv2/PIL 미설치 — 스플래시 skip ({e})")
        return

    vp = Path(video_path)
    if not vp.exists():
        print(f"[Intro] 비디오 없음 ({vp}) — 스플래시 skip")
        return

    cap = cv2.VideoCapture(str(vp))
    if not cap.isOpened():
        print("[Intro] VideoCapture 열기 실패 — 스플래시 skip")
        return

    fps = cap.get(cv2.CAP_PROP_FPS) or 30.0
    frame_ms = max(int(1000.0 / max(fps, 1.0)), 8)
    vw = int(cap.get(cv2.CAP_PROP_FRAME_WIDTH) or 800)
    vh = int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT) or 450)

    if vw > max_display_w:
        disp_w = max_display_w
        disp_h = max(1, int(vh * max_display_w / vw))
    else:
        disp_w, disp_h = vw, vh

    root = tk.Tk()
    root.withdraw()
    screen_w = root.winfo_screenwidth()
    screen_h = root.winfo_screenheight()

    TAG_H = 44
    total_h = disp_h + TAG_H
    x = max(0, (screen_w - disp_w) // 2)
    y = max(0, (screen_h - total_h) // 2)

    splash = tk.Toplevel(root)
    splash.overrideredirect(True)
    try:
        splash.attributes("-topmost", True)
        splash.attributes("-alpha", 0.0)
    except tk.TclError:
        pass
    splash.configure(bg="#0A0F1C")
    splash.geometry(f"{disp_w}x{total_h}+{x}+{y}")

    vid_label = tk.Label(splash, bg="#0A0F1C", borderwidth=0, highlightthickness=0)
    vid_label.place(x=0, y=0, width=disp_w, height=disp_h)

    tag_label = tk.Label(
        splash, text=tagline,
        bg="#0A0F1C", fg="#E67E22",
        font=("Segoe UI", 10, "italic"),
        borderwidth=0, highlightthickness=0,
    )
    tag_label.place(x=0, y=disp_h, width=disp_w, height=TAG_H)

    state = {"closed": False, "t_start": time.time()}

    def _safe_alpha(a):
        with contextlib.suppress(tk.TclError):
            splash.attributes("-alpha", max(0.0, min(1.0, a)))

    def _fade_to(target, duration_ms, done_cb=None):
        steps = max(int(duration_ms / 16), 1)
        start_alpha = float(splash.attributes("-alpha") or 0.0)

        def _step(i):
            if state["closed"]:
                return
            ratio = i / steps
            _safe_alpha(start_alpha + (target - start_alpha) * ratio)
            if i < steps:
                splash.after(16, lambda: _step(i + 1))
            elif done_cb:
                done_cb()

        _step(0)

    def _close():
        if state["closed"]:
            return
        state["closed"] = True
        with contextlib.suppress(Exception):
            cap.release()
        with contextlib.suppress(Exception):
            splash.destroy()
        with contextlib.suppress(Exception):
            root.quit()

    def _play_next_frame():
        if state["closed"]:
            return
        if (time.time() - state["t_start"]) > max_duration_s:
            _fade_to(0.0, fade_ms, done_cb=_close)
            return
        ret, frame = cap.read()
        if not ret:
            # 비디오 끝 — 페이드아웃 후 종료
            _fade_to(0.0, fade_ms, done_cb=_close)
            return
        rgb = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
        if (vw, vh) != (disp_w, disp_h):
            rgb = cv2.resize(rgb, (disp_w, disp_h), interpolation=cv2.INTER_AREA)
        img = Image.fromarray(rgb)
        photo = ImageTk.PhotoImage(img)
        vid_label.configure(image=photo)
        vid_label.image = photo  # GC 방지
        splash.after(frame_ms, _play_next_frame)

    # 페이드인 → 첫 프레임 재생 시작
    _fade_to(1.0, fade_ms, done_cb=_play_next_frame)

    try:
        root.mainloop()
    finally:
        with contextlib.suppress(Exception):
            root.destroy()


if __name__ == "__main__":
    # 단독 테스트
    show_intro_splash(Path(__file__).resolve().parent / "Design" / "logo_intro.mp4")
