"""Test: draw a line with real pointer events and verify the measurement
modal opens. Uses the app's own __test hook and CDP-style pointer dispatch."""
import os
import sys
import time

sys.stdout.reconfigure(encoding="utf-8", errors="replace")

from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.firefox.options import Options
from selenium.webdriver.firefox.service import Service

HERE = os.path.dirname(os.path.abspath(__file__))
GECKODRIVER = os.path.join(HERE, "geckodriver.exe")
BASE = "http://localhost:8000/field-capture.html?debug"

POINTER_DRAW_JS = """
(function(){
  try {
    const canvas = document.getElementById('sketchCanvas');
    if (!canvas) return 'no-canvas';
    if (typeof PointerEvent === 'undefined') return 'no-pointerevent';
    // Synthetic events: neutralize pointer capture (it throws for
    // non-real pointerIds and would abort the app's pointerdown handler).
    canvas.setPointerCapture = function(){};
    canvas.releasePointerCapture = function(){};
    canvas.hasPointerCapture = function(){ return false; };
    const rect = canvas.getBoundingClientRect();
    const startX = rect.left + rect.width * 0.3;
    const startY = rect.top + rect.height * 0.4;
    const endX = rect.left + rect.width * 0.7;
    const endY = rect.top + rect.height * 0.6;
    const opts = { bubbles: true, cancelable: true, pointerId: 1, pointerType: 'touch', isPrimary: true, clientX: startX, clientY: startY };
    canvas.dispatchEvent(new PointerEvent('pointerdown', opts));
    for (let i = 1; i <= 5; i++) {
      const x = startX + (endX - startX) * i / 5;
      const y = startY + (endY - startY) * i / 5;
      canvas.dispatchEvent(new PointerEvent('pointermove', { bubbles: true, cancelable: true, pointerId: 1, pointerType: 'touch', isPrimary: true, clientX: x, clientY: y }));
    }
    canvas.dispatchEvent(new PointerEvent('pointerup', { bubbles: true, cancelable: true, pointerId: 1, pointerType: 'touch', isPrimary: true, clientX: endX, clientY: endY }));
    return 'dispatched';
  } catch (err) {
    return 'ERROR: ' + err.message;
  }
})();
"""


def main():
    opts = Options()
    opts.headless = False
    svc = Service(executable_path=GECKODRIVER)
    d = webdriver.Firefox(options=opts, service=svc)
    d.set_window_size(480, 900)
    try:
        d.get(BASE)
        time.sleep(2)

        # Create job
        d.find_element(By.CSS_SELECTOR, '[data-action="newjob"]').click()
        time.sleep(0.8)

        # Open sketch
        d.find_element(By.CSS_SELECTOR, '[data-action="opensketch"]').click()
        time.sleep(0.8)

        # Inject synthetic photo
        d.execute_script("""
            const T = window.__test;
            const job = T.state.jobs[0];
            const sk = job.sketches[0];
            const c = document.createElement('canvas');
            c.width = 200; c.height = 150;
            const ctx = c.getContext('2d');
            ctx.fillStyle = '#cccccc'; ctx.fillRect(0,0,200,150);
            ctx.strokeStyle = '#333'; ctx.lineWidth = 4;
            ctx.beginPath(); ctx.moveTo(20,20); ctx.lineTo(180,130); ctx.stroke();
            sk.photo = { dataUrl: c.toDataURL('image/jpeg', 0.8), width: 200, height: 150 };
            T.saveState();
        """)
        d.execute_script(
            "const T=window.__test; T.ui.screen='sketch'; T.ui.sketchId=T.state.jobs[0].sketches[0].id; T.render();"
        )
        time.sleep(0.8)

        canvas = d.find_element(By.ID, "sketchCanvas")
        print("canvas found:", bool(canvas))

        # Draw a line using real pointer events
        result = d.execute_script(POINTER_DRAW_JS)
        print("draw result:", result)
        time.sleep(1)

        # Check for modal
        overlay = d.find_elements(By.CSS_SELECTOR, ".sheet-overlay")
        print("modal overlay present:", len(overlay) > 0)
        if overlay:
            sheet = d.find_element(By.CSS_SELECTOR, ".sheet")
            print("sheet text:", sheet.text[:200])

        # Check the line was actually created in state
        line_count = d.execute_script(
            "const T=window.__test; return T.state.jobs[0].sketches[0].lines.length"
        )
        print("lines in state:", line_count)

        # ---- Test dimension input ----
        qi = d.find_elements(By.ID, "quickTotalInches")
        print("quick input found:", len(qi) > 0)
        if qi:
            # Check the new layout: input flanked by +/- buttons
            input_row = d.execute_script("""
                const inp = document.getElementById('quickTotalInches');
                const row = inp.parentElement;
                const btns = row.querySelectorAll('button');
                return JSON.stringify({
                    btns: Array.from(btns).map(b => b.textContent.trim()),
                    inputFlex: inp.style.flex || 'none'
                });
            """)
            print("input row layout:", input_row)
            # Check 1/16 stepper layout
            frac_row = d.execute_script("""
                const labels = Array.from(document.querySelectorAll('.sheet-minimal div')).filter(d => d.textContent.trim() === '1/16');
                return labels.length > 0 ? '1/16 label present' : 'no 1/16 label';
            """)
            print("frac row:", frac_row)
            # Check chips
            chips = d.execute_script("""
                return Array.from(document.querySelectorAll('.sheet-minimal [data-action="setfraction"]')).map(c => c.textContent.trim());
            """)
            print("fraction chips:", chips)

            # Set value + dispatch input event (as the browser would)
            d.execute_script("""
                const inp = document.getElementById('quickTotalInches');
                inp.value = '12';
                inp.dispatchEvent(new Event('input', { bubbles: true }));
            """)
            time.sleep(0.5)
            val = d.execute_script(
                "const T=window.__test; const l=T.state.jobs[0].sketches[0].lines[0]; return JSON.stringify({feet:l.feet, inches:l.inches, sixteenths:l.sixteenths});"
            )
            print("line value after typing 12:", val)
            preview = d.find_elements(By.CSS_SELECTOR, "#quickPreview")
            if preview:
                print("preview shows:", preview[0].text)

            # Test the 1/16 stepper: click + twice -> sixteenths = 2 (1/8)
            d.find_element(By.CSS_SELECTOR, '[data-action="stepup"][data-field="sixteenths"]').click()
            time.sleep(0.3)
            d.find_element(By.CSS_SELECTOR, '[data-action="stepup"][data-field="sixteenths"]').click()
            time.sleep(0.5)
            val2 = d.execute_script(
                "const T=window.__test; const l=T.state.jobs[0].sketches[0].lines[0]; return JSON.stringify({feet:l.feet, inches:l.inches, sixteenths:l.sixteenths});"
            )
            print("after 2x 1/16 +:", val2)
            preview2 = d.find_elements(By.CSS_SELECTOR, "#quickPreview")
            if preview2:
                print("preview after 1/16 +:", preview2[0].text)

            # Test whole-inch stepper: click + on inches
            d.find_element(By.CSS_SELECTOR, '[data-action="stepup"][data-field="inches"]').click()
            time.sleep(0.5)
            val3 = d.execute_script(
                "const T=window.__test; const l=T.state.jobs[0].sketches[0].lines[0]; return JSON.stringify({feet:l.feet, inches:l.inches, sixteenths:l.sixteenths});"
            )
            print("after inches +:", val3)
            preview3 = d.find_elements(By.CSS_SELECTOR, "#quickPreview")
            if preview3:
                print("preview after inches +:", preview3[0].text)

        # Dump app DBG logs
        dbg = d.execute_script(
            "return window.__dbgLogs ? window.__dbgLogs.join('\\n') : '(none)'"
        )
        print("== App [DBG] logs ==")
        print(dbg)
    finally:
        d.quit()


if __name__ == "__main__":
    main()