import sys, os, time, shutil
from pathlib import Path
sys.path.append(str(Path("05_Production_Pipeline").resolve()))
from invisible_playwright import InvisiblePlaywright
from muse_invpw_driver import DEFAULT_PROFILE, extract_tail_frame
from run_shot import ensure_audio_guard
import cv2

def test_clean_flow():
    shot_id = "ep01_scene01_shot01"
    start_frame = Path("04_Assets/keyframes/ep01_scene01_shot01/start_frame_720p.png").resolve()
    target_video = Path("04_Assets/videos/ep01_scene01_shot01_10s.mp4").resolve()
    target_video.parent.mkdir(parents=True, exist_ok=True)
    temp_dl = Path("04_Assets/temp_downloads/shot01_clean_flow.mp4").resolve()
    temp_dl.parent.mkdir(parents=True, exist_ok=True)
    downloads_dir = Path.home() / "Downloads"

    raw_prompt = (
        "Cú máy bay lướt êm ả dọc theo dòng sông biếc uốn lượn ngoại ô kinh thành Đại Minh Gia Tĩnh. "
        "Mặt nước trong veo như ngọc phản chiếu rặng liễu tơ mềm và làn sương sớm mai lảng bảng. "
        "Cảnh sắc mùa xuân thanh bình, xa xa thoáng bóng thuyền nan lướt nhẹ, 24fps cinematic drama. "
        "Âm thanh: Tiếng nước sông vỗ nhẹ vào bờ đất, tiếng mái chèo khua nước êm đềm từ xa, tiếng gió xuân mát rượi lướt qua rặng liễu."
    )
    prompt = ensure_audio_guard(raw_prompt)

    print("[1/5] Mở https://muse.ai để làm ấm session và kết nối VM...")
    with InvisiblePlaywright(profile_dir=DEFAULT_PROFILE, headless=True) as ctx:
        page = ctx.pages[0] if ctx.pages else ctx.new_page()
        page.on("response", lambda r: print(f"    [NET RESP {r.status}] {r.url[:80]}") if any(k in r.url for k in ["falco", "vm/wake", "token"]) else None)

        page.goto("https://muse.ai", wait_until="domcontentloaded", timeout=30000)
        time.sleep(4)

        # Chuyển sang đoạn chat mới qua nút bấm
        print("      Bấm nút 'Đoạn chat phụ mới'...")
        new_chat_btn = page.locator('button[aria-label="Đoạn chat phụ mới"]').first
        if new_chat_btn.count() > 0 and new_chat_btn.is_visible():
            new_chat_btn.click()
            time.sleep(3)
        else:
            page.goto("https://muse.ai/thread/new", wait_until="domcontentloaded")
            time.sleep(3)

        print(f"      ✓ Đã sẵn sàng luồng mới ({page.url})")

        # 2. Upload start frame
        if start_frame.exists():
            print(f"[2/5] Uploading Start Frame: {start_frame.name}...")
            file_input = page.locator('input[type="file"]').first
            if file_input.count() > 0:
                file_input.set_input_files(str(start_frame))
                time.sleep(3)
                print("      ✓ Đã upload ảnh thành công!")

        # 3. Gõ prompt và gửi
        print("[3/5] Gõ prompt và gửi lệnh...")
        chat_box = page.locator('textarea, [placeholder*="Nhắn tin"], [placeholder*="Message"], [role="textbox"]').first
        chat_box.click()
        time.sleep(1)
        page.keyboard.insert_text(prompt)
        time.sleep(1)
        page.keyboard.press("Space")
        time.sleep(1)

        dl_sel = 'button:has-text("Tải video xuống"), button[aria-label*="Tải video xuống"], button[data-pel="media_download"]'
        stop_sel = 'button:has-text("Dừng"), button[aria-label*="Dừng"], button:has-text("Stop")'
        pre_dl_cnt = page.locator(dl_sel).count()

        send_btn = page.locator('button[data-pel-click="chat_send_message"], button[aria-label="Gửi"]').first
        if send_btn.count() > 0 and send_btn.is_visible():
            send_btn.click()
        else:
            page.keyboard.press("Enter")
        time.sleep(3)

        # Kiểm tra gửi thành công
        for s in range(15):
            stop_cnt = page.locator(stop_sel).count()
            sending = page.locator('text="Vẫn đang gửi"').count()
            print(f"      [Check {s+1}s] stop_btn={stop_cnt}, still_sending={sending}")
            if stop_cnt > 0 and sending == 0:
                print("      🎉 Tuyệt vời! Prompt đã được gửi trực tiếp vào engine (không bị kẹt 'Vẫn đang gửi')!")
                break
            time.sleep(2)

        # 4. Giám sát render tối đa 240s
        print("[4/5] Giám sát tiến độ sinh video...")
        start_time = time.time()
        video_downloaded = False
        task_started = False

        for i in range(48): # 48 * 5s = 240s
            time.sleep(5)
            elapsed = int(time.time() - start_time)
            stop_cnt = page.locator(stop_sel).count()
            curr_dl_cnt = page.locator(dl_sel).count()

            if stop_cnt > 0:
                task_started = True

            print(f"      [{elapsed:3d}s] stop={stop_cnt}, dl_btn={curr_dl_cnt}, task_started={task_started}")

            # Chụp màn hình tiến độ mỗi 30s
            if elapsed % 30 == 0:
                page.screenshot(path=f"04_Assets/clean_render_{elapsed}s.png")

            # Khi hoàn tất render
            if (task_started and stop_cnt == 0 and elapsed >= 35) or (curr_dl_cnt > pre_dl_cnt and elapsed >= 35):
                print(f"\n🎉 Render hoàn tất sau {elapsed}s! Đang tải file video...")
                time.sleep(3)
                page.screenshot(path="04_Assets/clean_render_done.png")

                # Bấm nút download
                new_dl_btns = page.locator(dl_sel)
                if new_dl_btns.count() > 0:
                    btn = new_dl_btns.last
                    btn.scroll_into_view_if_needed()
                    click_time = time.time()
                    before_dls = {f.name: f.stat().st_mtime for f in downloads_dir.glob("*.mp4")}

                    try:
                        print("  [*] Thử tải qua expect_download...")
                        with page.expect_download(timeout=10000) as dl_info:
                            btn.click(force=True)
                        dl = dl_info.value
                        if temp_dl.exists():
                            temp_dl.unlink()
                        dl.save_as(str(temp_dl))
                        if temp_dl.exists() and temp_dl.stat().st_size > 500000:
                            print(f"  ✓ Tải thành công qua expect_download: {temp_dl.stat().st_size} bytes!")
                            video_downloaded = True
                    except Exception as e_dl:
                        print(f"  [-] expect_download: {e_dl}")

                    if not video_downloaded:
                        print("  [*] Quét thư mục Downloads...")
                        for _ in range(12):
                            time.sleep(1)
                            new_files = [
                                f for f in downloads_dir.glob("*.mp4")
                                if (f.name not in before_dls or f.stat().st_mtime > click_time - 1.0)
                                and f.stat().st_size > 500000
                            ]
                            if new_files:
                                new_files.sort(key=lambda x: x.stat().st_mtime, reverse=True)
                                if temp_dl.exists():
                                    temp_dl.unlink()
                                shutil.move(str(new_files[0]), str(temp_dl))
                                print(f"  ✓ Bắt được file từ Downloads: {temp_dl.stat().st_size} bytes!")
                                video_downloaded = True
                                break

                # Fallback JS Blob
                if not video_downloaded:
                    print("  [*] Thử trích xuất JS Blob từ DOM player...")
                    videos = page.locator('video').all()
                    for idx, v in enumerate(reversed(videos)):
                        try:
                            dur = v.evaluate("el => el.duration")
                            vw = v.evaluate("el => el.videoWidth")
                            vh = v.evaluate("el => el.videoHeight")
                            if dur and dur < 6.0 and vw and vw < 500:
                                continue
                            blob_url = v.get_attribute("src") or v.evaluate("el => el.currentSrc")
                            if blob_url and blob_url.startswith("blob:"):
                                import base64
                                b64 = page.evaluate("""async (url) => {
                                    const res = await fetch(url);
                                    const b = await res.blob();
                                    return new Promise((resolve, reject) => {
                                        const r = new FileReader();
                                        r.onloadend = () => resolve(r.result.split(',')[1]);
                                        r.onerror = reject;
                                        r.readAsDataURL(b);
                                    });
                                }""", blob_url)
                                if b64:
                                    raw_bytes = base64.b64decode(b64)
                                    if len(raw_bytes) > 500000:
                                        temp_dl.write_bytes(raw_bytes)
                                        print(f"  ✓ Trích xuất JS Blob thành công ({vw}x{vh}): {len(raw_bytes)} bytes!")
                                        video_downloaded = True
                                        break
                        except Exception as e_blob:
                            print(f"      [-] Blob error: {e_blob}")

                if video_downloaded:
                    break

        if not video_downloaded or not temp_dl.exists():
            print("[!] Thất bại: Không thu hoạch được video.")
            page.screenshot(path="04_Assets/clean_render_failed.png")
            return False

        # Lưu master video và trích xuất tail frame
        shutil.copy2(str(temp_dl), str(target_video))
        print(f"\n=======================================================")
        print(f"🎉 MASTER VIDEO: {target_video.name} ({target_video.stat().st_size:,} bytes)")
        print(f"=======================================================\n")

        # Trích xuất Tail Frame 239
        tf = extract_tail_frame(target_video, shot_id)
        print(f"✓ Tail frame 239 trích xuất thành công: {tf}")
        return True

if __name__ == '__main__':
    ok = test_clean_flow()
    sys.exit(0 if ok else 1)
