import time,re,json,requests,io,random
import numpy as np
from PIL import Image
from scipy import ndimage
from selenium import webdriver
from selenium.webdriver.firefox.options import Options
from selenium.webdriver.common.by import By
from selenium.webdriver.common.action_chains import ActionChains
urllib3=__import__('urllib3'); urllib3.disable_warnings()

def driver():
    o=Options(); o.set_preference('dom.webdriver.enabled',False)
    o.set_preference('network.http.referer.spoofSource',True)
    o.set_preference('network.http.referer.defaultReferrer','https://ein38eu95792b.4656hd15.cc/')
    return webdriver.Firefox(options=o)

def find_gap(bg, sl):
    g=np.array(bg.convert('L')).astype(np.float32)
    sa=np.array(sl); alpha=sa[:,:,3]>128
    ys,xs=np.where(alpha)
    if len(xs)==0: return None
    ax0,ay0,ax1,ay1=xs.min(),ys.min(),xs.max(),ys.max()
    aw,ah=ax1-ax0+1,ay1-ay0+1
    cands=[]
    for th in [50,55,60,65,70,75,80,85,90]:
        dark=g<th; lab,n=ndimage.label(dark)
        for i in range(1,n+1):
            ys2,xs2=np.where(lab==i); area=len(xs2)
            if area<300: continue
            x0,x1,y0,y1=xs2.min(),xs2.max(),ys2.min(),ys2.max()
            w,h=x1-x0+1,y1-y0+1
            # shape size close to piece
            if abs(w-aw)<=18 and abs(h-ah)<=18:
                cands.append((abs(w-aw)+abs(h-ah),th,int(x0),int(y0),int(w),int(h),int(area)))
    if not cands: return None
    cands.sort()
    c=cands[0]
    target_left=c[2]-int(ax0)
    return target_left,c,(int(ax0),int(ay0),aw,ah)

for attempt in range(1,5):
    d=driver(); d.set_page_load_timeout(40)
    try:
        d.get('http://127.0.0.1:9999/geetest_page.html')
        for _ in range(30):
            time.sleep(0.4)
            if d.execute_script("return document.querySelectorAll('.geetest_bg').length>0"): break
        time.sleep(1.2)
        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')};""")
        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')
        res=find_gap(bg,sl)
        if not res: print('attempt',attempt,'no gap'); d.quit(); continue
        target_left,c,ab=res; scale=info['bg']['w']/bg.size[0]; drag=target_left*scale
        print(f'attempt {attempt} gap={c} alpha_bbox={ab} target_left={target_left} drag={drag:.2f} initdx={info["slice"]["l"]-info["bg"]["l"]:.2f}')
        btn=d.find_element(By.CSS_SELECTOR,'.geetest_btn')
        ActionChains(d).move_to_element(btn).perform(); time.sleep(random.uniform(0.3,0.6))
        ActionChains(d).click_and_hold(btn).perform(); time.sleep(random.uniform(0.15,0.3))
        steps=random.randint(30,38); moved=0.0
        for i in range(1,steps+1):
            t=i/steps; p=1-(1-t)**3
            target=drag*p
            ActionChains(d).move_by_offset(target-moved,0).perform(); moved=target
            time.sleep(random.uniform(0.018,0.04))
        time.sleep(random.uniform(0.15,0.3))
        ActionChains(d).release().perform()
        val=None
        for _ in range(20):
            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)
        print('  resultText',d.execute_script("var e=document.querySelector('.geetest_result');return e?e.innerText:null"))
        if val:
            open('gt_result.json','w').write(json.dumps(val,ensure_ascii=False)); d.quit(); break
        d.quit()
    except Exception as e:
        print('attempt',attempt,'ERR',str(e)[:160])
        try: d.quit()
        except: pass
