import time,re,json,requests,io,random,subprocess
import numpy as np, cv2
from PIL import Image
from selenium import webdriver
from selenium.webdriver.firefox.options import Options
from selenium.webdriver.firefox.service import Service
BASE='http://ein38eu95792b.4656hd15.cc/geetest_page.html'
def mk():
    o=Options(); o.set_preference('dom.webdriver.enabled',False); o.set_preference('network.trr.mode',5); o.set_preference('network.proxy.type',0)
    o.set_preference('general.useragent.override','Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:136.0) Gecko/20100101 Firefox/136.0')
    return webdriver.Firefox(service=Service('./gd0371/geckodriver'), options=o)
def xdo(*a): subprocess.run(['xdotool',*map(str,a)],check=False)
def cv_x(bg,sl,top):
    b=np.array(bg.convert('L')); s=np.array(sl.convert('RGBA'))
    sg=cv2.cvtColor(s,cv2.COLOR_RGBA2GRAY)[:,:] if s.shape[2]==4 else np.array(sl.convert('L'))
    h,w=sg.shape
    if top<0 or top+h>b.shape[0]: top=max(0,min(b.shape[0]-h,top))
    strip=b[top:top+h,:]
    xs=[]
    for lo,hi in [(50,100),(80,160),(110,220)]:
        be=cv2.Canny(strip,lo,hi); se=cv2.Canny(sg,lo,hi)
        if be.sum()==0 or se.sum()==0: continue
        res=cv2.matchTemplate(be,se,cv2.TM_CCOEFF_NORMED)
        _,mx,_,ml=cv2.minMaxLoc(res)
        xs.append((ml[0],mx))
    if not xs: return 0,0
    xs_sorted=sorted(x[0] for x in xs)
    return xs_sorted[len(xs_sorted)//2], max(x[1] for x in xs)
def drag(D,X,Y):
    xdo('mousemove',X,Y); time.sleep(0.25); xdo('mousedown',1); time.sleep(0.15)
    pos=0
    while pos<D+3:
        pos=min(D+3,pos+random.uniform(2,6)); xdo('mousemove',int(X+pos),Y+random.choice([0,0,1,-1])); time.sleep(random.uniform(0.012,0.035))
    while pos>D: pos-=random.choice([1,2]); xdo('mousemove',int(X+pos),Y); time.sleep(0.02)
    xdo('mouseup',1)
for load in range(1,3):
    if load>1: time.sleep(30)
    d=mk(); d.set_page_load_timeout(40)
    try:
        d.set_window_position(0,0); d.set_window_size(1000,820); d.get(BASE)
        ok=False
        for _ in range(50):
            time.sleep(0.5)
            if d.execute_script("return document.querySelectorAll('.geetest_bg').length>0"): ok=True; break
        if not ok: print('load',load,'no captcha'); d.quit(); continue
        deltas=[-1,-2,0,1]
        for retry,delta in enumerate(deltas,1):
            time.sleep(0.8)
            info=d.execute_script("""function r(s){var e=document.querySelector(s);if(!e)return null;var b=e.getBoundingClientRect();return {t:b.top,l:b.left,w:b.width,h:b.height,bg:getComputedStyle(e).backgroundImage};}return {bg:r('.geetest_bg'),slice:r('.geetest_slice'),slicebg:r('.geetest_slice_bg'),btn:r('.geetest_btn'),sx:window.mozInnerScreenX,sy:window.mozInnerScreenY};""")
            if not info.get('bg'): print(' no bg'); break
            def dl(u):
                m=re.search(r'url\("?([^")]+)"?\)',u or '');return requests.get(m.group(1).replace('http://','https://'),timeout=20,verify=False).content
            bg=Image.open(io.BytesIO(dl(info['bg']['bg']))).convert('RGB'); sl=Image.open(io.BytesIO(dl(info['slicebg']['bg']))).convert('RGBA')
            top=int(round((info['slice']['t']-info['bg']['t'])*bg.size[1]/info['bg']['h'])); top=max(0,min(bg.size[1]-sl.size[1],top))
            x,score=cv_x(bg,sl,top); x=max(0,min(bg.size[0]-80,x+delta)); scale=info['bg']['w']/bg.size[0]; D=x*scale
            print(f'load{load} retry{retry} delta={delta} cv_x={x-delta}({score:.3f}) x={x} D={D:.2f}')
            X=int(info['sx']+info['btn']['l']+info['btn']['w']/2); Y=int(info['sy']+info['btn']['t']+info['btn']['h']/2)
            drag(D,X,Y)
            val=None
            for _ in range(14):
                time.sleep(0.5); val=d.execute_script('return window.validateResult')
                if val: break
            print('  validate',json.dumps(val,ensure_ascii=False) if val else None)
            if val:
                open('gt_result.json','w').write(json.dumps(val,ensure_ascii=False)); d.quit(); raise SystemExit
        d.quit()
    except SystemExit: break
    except Exception as ex:
        print('load',load,'ERR',str(ex)[:100])
        try:d.quit()
        except:pass
