#!/usr/bin/env python3
"""
Argos QA Tester - 네이버블로그 Keyword Analysis FINAL (corrected)
Key findings from debug:
1. page.fill() doesn't trigger React onChange - must use React nativeInputValueSetter
2. The step indicator has button text "0키워드 분석" - avoid matching it
3. After React setter, button becomes enabled and API fires correctly
"""

import time
from playwright.sync_api import sync_playwright

SCREENSHOT_DIR = "/home/jay/workspace/memory/reports/task-1933-screenshots"
BASE_URL = "http://localhost:8000/dashboard/"

results = []
api_calls = []

def log_result(status, test_name, detail=""):
    icon = {"PASS": "[PASS]", "FAIL": "[FAIL]", "WARN": "[WARN]"}.get(status, "[INFO]")
    msg = f"{icon} {test_name}"
    if detail:
        msg += f" — {detail}"
    print(msg)
    results.append({"status": status, "test": test_name, "detail": detail})

def set_react_input(page, selector, value):
    """Set input value in a way that triggers React onChange."""
    result = page.evaluate(
        """
        ([sel, value]) => {
            const inp = document.querySelector(sel);
            if (!inp) return {ok: false, error: 'not found'};
            const nativeInputValueSetter = Object.getOwnPropertyDescriptor(
                window.HTMLInputElement.prototype, 'value'
            ).set;
            nativeInputValueSetter.call(inp, value);
            inp.dispatchEvent(new Event('input', { bubbles: true }));
            inp.dispatchEvent(new Event('change', { bubbles: true }));
            return {ok: true, value: inp.value};
        }
        """,
        [selector, value]
    )
    return result

def click_analyze_button(page):
    """Click the 분석 button (not the step indicator)."""
    # Find the submit button within the keyword input area specifically
    result = page.evaluate("""
        () => {
            // Find buttons with '분석' text, exclude step indicators
            const btns = document.querySelectorAll('button');
            for (const btn of btns) {
                const txt = btn.textContent.trim();
                if (txt === '분석' || txt === '분석 중...') {
                    btn.click();
                    return {clicked: true, text: txt, disabled: btn.disabled};
                }
            }
            // Fallback: any button with only '분석' in a form-like context
            for (const btn of btns) {
                if (btn.textContent.includes('분석') && !btn.textContent.includes('경쟁') && btn.textContent.length < 10) {
                    btn.click();
                    return {clicked: true, text: btn.textContent.trim(), disabled: btn.disabled};
                }
            }
            return {clicked: false, available: Array.from(btns).map(b => b.textContent.trim().substring(0, 20))};
        }
    """)
    return result

def run_tests():
    with sync_playwright() as p:
        browser = p.chromium.launch(headless=True)
        context = browser.new_context(viewport={"width": 1440, "height": 900})
        page = context.new_page()

        # Network monitoring
        def on_req(req):
            if "naver-blog" in req.url:
                api_calls.append({"type": "req", "method": req.method, "url": req.url})
                print(f"    [REQ] {req.method} {req.url}")

        def on_res(res):
            if "naver-blog" in res.url:
                api_calls.append({"type": "res", "status": res.status, "url": res.url})
                print(f"    [RES] {res.status} {res.url}")

        page.on("request", on_req)
        page.on("response", on_res)

        # ══ TEST 1: Navigate to dashboard ══════════════════════════════════════
        print("\n=== TEST 1: Navigate to dashboard ===")
        page.goto(BASE_URL, wait_until="domcontentloaded")
        page.wait_for_timeout(5000)
        page.screenshot(path=f"{SCREENSHOT_DIR}/03_keyword_01_loaded.png")
        log_result("PASS", "Dashboard navigation", page.url)

        # ══ TEST 2: Click 네이버블로그 tab ══════════════════════════════════════
        print("\n=== TEST 2: Click 네이버블로그 tab ===")
        tab = page.locator("button:has-text('네이버블로그')").first
        tab.wait_for(state="visible", timeout=5000)
        tab.click()
        page.wait_for_timeout(3000)
        page.screenshot(path=f"{SCREENSHOT_DIR}/03_keyword_02_tab_active.png")
        log_result("PASS", "Click 네이버블로그 tab", "3s render wait complete")

        # ══ TEST 3: Verify Step 0 UI elements ══════════════════════════════════
        print("\n=== TEST 3: Verify 키워드 분석 step UI ===")
        # Verify placeholder text
        inp_placeholder = page.locator("input[placeholder*='키워드를 입력하세요']").first
        if inp_placeholder.is_visible(timeout=3000):
            ph = inp_placeholder.get_attribute("placeholder")
            log_result("PASS", "Keyword input present", f"placeholder: '{ph}'")
        else:
            log_result("FAIL", "Keyword input", "Not visible")

        # Verify exact 분석 button (not step indicator)
        btn_check = page.evaluate("""
            () => {
                const btns = document.querySelectorAll('button');
                const found = [];
                for (const btn of btns) {
                    if (btn.textContent.trim() === '분석') {
                        found.push({text: btn.textContent.trim(), disabled: btn.disabled, cls: btn.className.substring(0, 60)});
                    }
                }
                return found;
            }
        """)
        if btn_check:
            log_result("PASS", "분석 button (exact text match)", f"Found: {btn_check}")
        else:
            log_result("WARN", "분석 button exact match", "Not found with exact text '분석'")

        # ══ TEST 4: Type '실손보험' using React-compatible method ═══════════════
        print("\n=== TEST 4: Type '실손보험' (React-compatible) ===")
        # Use React nativeInputValueSetter to properly trigger onChange
        result = set_react_input(page, "input[placeholder*='키워드를 입력하세요']", "실손보험")
        print(f"  set_react_input result: {result}")

        # Verify
        inp_val = page.locator("input[placeholder*='키워드를 입력하세요']").first.input_value()
        if "실손보험" in inp_val:
            log_result("PASS", "Type keyword '실손보험'", f"DOM value: '{inp_val}'")
        else:
            log_result("FAIL", "Type keyword '실손보험'", f"DOM value: '{inp_val}'")

        # Check button disabled state after typing
        btn_state = page.evaluate("""
            () => {
                const btns = document.querySelectorAll('button');
                for (const btn of btns) {
                    if (btn.textContent.trim() === '분석') {
                        return {disabled: btn.disabled, opacity: window.getComputedStyle(btn).opacity};
                    }
                }
                return null;
            }
        """)
        print(f"  Button state after typing: {btn_state}")

        page.screenshot(path=f"{SCREENSHOT_DIR}/03_keyword_03_typed.png")

        # ══ TEST 5: Click 분석 button ════════════════════════════════════════════
        print("\n=== TEST 5: Click 분석 button ===")
        click_result = click_analyze_button(page)
        print(f"  click_analyze_button result: {click_result}")

        if click_result.get("clicked"):
            log_result("PASS", "Click 분석 button",
                       f"text='{click_result['text']}', disabled={click_result['disabled']}")
        else:
            log_result("FAIL", "Click 분석 button",
                       f"Could not click. Available: {click_result.get('available', [])[:5]}")

        page.wait_for_timeout(1000)
        page.screenshot(path=f"{SCREENSHOT_DIR}/03_keyword_04_analyzing.png")

        # ══ TEST 6: Poll 30s for results ════════════════════════════════════════
        print("\n=== TEST 6: Poll for results (30s) ===")
        result_found = False
        error_found = False
        error_text = ""
        row_count = 0

        for attempt in range(15):
            time.sleep(2)
            elapsed = (attempt + 1) * 2
            print(f"  [{elapsed}s] Attempt {attempt+1}/15...")

            try:
                body = page.locator("body").inner_text(timeout=500)

                # Loading indicator
                if "분석 중" in body:
                    print("    (분석 중...)")
                    continue

                # Results appeared
                if "연관 키워드 분석 결과" in body:
                    result_found = True
                    # Count result rows
                    row_count = page.locator("tbody tr").count()
                    log_result("PASS", "Keyword analysis results appeared",
                               f"'연관 키워드 분석 결과' at {elapsed}s, {row_count} rows")
                    break

                if "선택한 키워드 순위" in body:
                    # Check if table also visible
                    tables = page.locator("table").count()
                    if tables > 0:
                        result_found = True
                        row_count = page.locator("tbody tr").count()
                        log_result("PASS", "Results UI visible",
                                   f"Selection + table at {elapsed}s, {row_count} rows")
                        break
                    elif attempt > 5:
                        # Selection area visible but no table yet - still loading?
                        print(f"    Selection area visible, waiting for table...")

                # Error check (in the keyword input section)
                err_divs = page.locator(".bg-red-50, .text-red-700")
                for i in range(err_divs.count()):
                    try:
                        txt = err_divs.nth(i).inner_text(timeout=200)
                        if txt.strip() and ("오류" in txt or "실패" in txt or "error" in txt.lower()):
                            # Not from history (history errors show "실패: AI 글 생성...")
                            if "AI 글 생성" not in txt:
                                error_found = True
                                error_text = txt.strip()
                                log_result("FAIL", "Keyword analysis error",
                                           f"Error at {elapsed}s: '{error_text[:200]}'")
                                break
                    except Exception:
                        pass
                if error_found:
                    break

            except Exception as e:
                print(f"    Poll error: {e}")

        # ══ TEST 7: Screenshot ════════════════════════════════════════════════
        print("\n=== TEST 7: Screenshot of results ===")
        page.screenshot(path=f"{SCREENSHOT_DIR}/03_keyword_05_results.png")
        print("  Saved: 03_keyword_05_results.png")
        log_result("PASS", "Screenshot saved", "03_keyword_05_results.png")

        # ══ TEST 8-10: Table interaction (if results found) ═══════════════════
        if result_found:
            print("\n=== TEST 8: Check keyword data columns ===")
            hdrs = page.locator("th").all_text_contents()
            hdrs_clean = [h.strip() for h in hdrs if h.strip()]
            print(f"  Column headers: {hdrs_clean}")

            # Expected: 키워드, PC 검색량, 모바일 검색량, PC CTR, 모바일 CTR, CPC, 경쟁도
            expected = {"키워드", "PC 검색량", "모바일 검색량", "경쟁도"}
            found_e = expected & {h.replace(" ▼", "").replace(" ▲", "").strip() for h in hdrs_clean}
            if len(found_e) >= 3:
                log_result("PASS", "Keyword data columns present",
                           f"Found expected: {found_e} | All headers: {hdrs_clean}")
            else:
                log_result("WARN", "Keyword data columns",
                           f"Only {len(found_e)} expected cols found: {found_e}")

            print(f"\n=== TEST 9: Sort by column headers ===")
            sort_success = 0
            for i, hdr in enumerate(hdrs_clean[:7]):
                try:
                    h = page.locator("th").nth(i)
                    if h.is_visible(timeout=200):
                        h.click()
                        page.wait_for_timeout(700)
                        updated = h.inner_text(timeout=300)
                        if "▼" in updated or "▲" in updated:
                            log_result("PASS", f"Sort column '{hdr}'",
                                       f"Indicator: '{updated}'")
                            sort_success += 1
                            if sort_success >= 2:
                                break
                except Exception as e:
                    log_result("WARN", f"Sort '{hdr}'", str(e)[:60])

            page.screenshot(path=f"{SCREENSHOT_DIR}/03_keyword_06_after_sort.png")
            print("  Screenshot: 03_keyword_06_after_sort.png")

            print(f"\n=== TEST 10: Click keyword rows for selection ===")
            rows = page.locator("tbody tr")
            rc = rows.count()
            sel_count = 0
            print(f"  tbody rows: {rc}")

            if rc > 0:
                for i in range(min(rc, 3)):
                    try:
                        row = rows.nth(i)
                        row_txt = row.inner_text(timeout=300)
                        row.click()
                        page.wait_for_timeout(500)
                        # Verify selection updated
                        body_now = page.locator("body").inner_text(timeout=400)
                        if f"{sel_count+1}/5개 선택" in body_now or "✓" in body_now:
                            sel_count += 1
                            log_result("PASS", f"Select keyword row {i+1}",
                                       f"keyword: '{row_txt[:30].strip()}'")
                    except Exception as e:
                        log_result("WARN", f"Row {i+1} click", str(e)[:60])

                if sel_count == 0:
                    # Try checking counter another way
                    try:
                        body_now = page.locator("body").inner_text(timeout=400)
                        counter = [l for l in body_now.split("\n") if "개 선택" in l]
                        log_result("WARN", "Row selection check",
                                   f"Counter lines: {counter[:2]}")
                    except Exception:
                        pass

            page.screenshot(path=f"{SCREENSHOT_DIR}/03_keyword_07_after_selection.png")
            print("  Screenshot: 03_keyword_07_after_selection.png")

        elif error_found:
            log_result("FAIL", "Keyword analysis result",
                       f"Error: '{error_text[:200]}'")
            page.screenshot(path=f"{SCREENSHOT_DIR}/03_keyword_06_error.png")
        else:
            # No result - check final page state
            body_final = page.locator("body").inner_text(timeout=1000)
            analyze_calls = [c for c in api_calls if "keyword-analysis" in c.get("url", "")]

            if analyze_calls:
                log_result("WARN", "API called but no results visible",
                           f"{len(analyze_calls)} calls but no table appeared")
            else:
                log_result("FAIL", "Keyword analysis did not trigger API",
                           "Check input React integration")

            # Show any partial results
            if "연관" in body_final or "검색" in body_final:
                log_result("WARN", "Partial results content",
                           "Keyword-like content found but no table rendered")
            print(f"\n  Final page body sample:\n{body_final[:500]}")

        # ══ API Summary ══════════════════════════════════════════════════════
        print("\n=== API CALL SUMMARY ===")
        naver_calls = [c for c in api_calls if "naver-blog" in c.get("url", "")]
        analyze_calls = [c for c in naver_calls if "keyword-analysis" in c.get("url", "")]

        print(f"  Total naver-blog calls: {len(naver_calls)}")
        for c in naver_calls:
            s = c.get("status", "")
            print(f"  [{c['type'].upper()}] {c.get('method', '')} {c['url']} {s}")

        if analyze_calls:
            api_errors = [c for c in analyze_calls if isinstance(c.get("status"), int) and c["status"] >= 400]
            if api_errors:
                log_result("FAIL", "keyword-analysis API errors",
                           f"{len(api_errors)} failed: {[c['status'] for c in api_errors]}")
            else:
                res_calls = [c for c in analyze_calls if c["type"] == "res"]
                log_result("PASS", "keyword-analysis API",
                           f"Called {len(analyze_calls)} times, responses: {[c.get('status') for c in res_calls]}")
        else:
            log_result("FAIL", "keyword-analysis API never called")

        page.screenshot(path=f"{SCREENSHOT_DIR}/03_keyword_08_final.png")
        print("  Final screenshot: 03_keyword_08_final.png")
        browser.close()

    # ══ FINAL REPORT ═══════════════════════════════════════════════════════
    print("\n" + "="*65)
    print("  ARGOS QA REPORT — 네이버블로그 Keyword Analysis Feature")
    print("="*65)
    pass_c = sum(1 for r in results if r["status"] == "PASS")
    fail_c = sum(1 for r in results if r["status"] == "FAIL")
    warn_c = sum(1 for r in results if r["status"] == "WARN")
    print(f"\n  PASS: {pass_c}  |  FAIL: {fail_c}  |  WARN: {warn_c}  |  TOTAL: {len(results)}\n")
    print("-"*65)
    for r in results:
        icon = {"PASS": "[PASS]", "FAIL": "[FAIL]", "WARN": "[WARN]"}.get(r["status"], "[?]")
        print(f"  {icon} {r['test']}")
        if r["detail"]:
            for line in r["detail"].split("\n")[:2]:
                if line.strip():
                    print(f"           {line.strip()[:100]}")
    print("="*65)

if __name__ == "__main__":
    run_tests()
