#!/usr/bin/env python3
"""عدسة النقوش SAM 2 — نسخة مطورة"""
import cv2
import numpy as np
import base64, json, pickle, os, torch
from http.server import HTTPServer, BaseHTTPRequestHandler

SAM2_DIR = '/var/www/html/sam2'
MODEL_PATH = os.path.join(SAM2_DIR, 'sam2_hiera_large.pt')
CFG_PATH = 'configs/sam2/sam2_hiera_l.yaml'

# Load model once at startup
print("⏳ جاري تحميل SAM 2...")
from sam2.build_sam import build_sam2
from sam2.sam2_image_predictor import SAM2ImagePredictor
device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
sam2_model = build_sam2(CFG_PATH, MODEL_PATH, device=device)
predictor = SAM2ImagePredictor(sam2_model, device=device)
print(f"✅ SAM 2 جاهز على {device}")

HTML_PAGE = """<!DOCTYPE html>
<html lang="ar" dir="rtl">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
    <meta name="apple-mobile-web-app-capable" content="yes">
    <meta name="apple-mobile-web-app-title" content="SAM 2">
    <link rel="icon" type="image/png" href="/favicon.png">
    <link rel="apple-touch-icon" href="/favicon.png">
    <title>عدسة النقوش SAM 2</title>
    <style>
        *{box-sizing:border-box;margin:0;padding:0}
        body{font-family:'Segoe UI',sans-serif;background:#1e1e24;color:#f5f5f5;padding:15px;display:flex;flex-direction:column;align-items:center}
        .card{background:#2b2b36;padding:15px;border-radius:10px;width:100%;max-width:800px;display:flex;flex-direction:column;gap:10px}
        .row{display:flex;justify-content:center;gap:10px;flex-wrap:wrap}
        button{background:#ffcc00;color:#1e1e24;border:none;padding:10px 18px;border-radius:5px;cursor:pointer;font-weight:bold;font-size:14px}
        button:hover{background:#e6b800}
        #result{display:none;width:100%;max-width:800px;margin-top:10px;position:relative}
        #result img{width:100%;border-radius:8px;border:2px solid #444;display:block;touch-action:none}
        #overlayCanvas{pointer-events:none}
        #loading{display:none;color:#ffcc00;text-align:center;padding:10px}
        #magnifier{display:none;position:fixed;z-index:99999;width:50px;height:50px;border-radius:50%;border:2px solid #ffcc00;box-shadow:0 0 10px rgba(255,204,0,0.6);pointer-events:none;overflow:hidden;background:#fff}
        #magnifier img{position:absolute;top:0;left:0;max-width:none;max-height:none;border:none}
        .no-callout{-webkit-touch-callout:none!important;-webkit-user-select:none!important;user-select:none!important}
        #waitToast{display:none;position:fixed;top:50%;left:50%;transform:translate(-50%,-50%);z-index:99998;background:#2b2b36;color:#ffcc00;padding:20px 30px;border-radius:12px;border:1px solid #ffcc00;font-weight:bold;font-size:16px;box-shadow:0 4px 20px rgba(0,0,0,0.5);text-align:center}
    </style>
</head>
<body>
    <div id="magnifier"><img id="magImg"></div>
    <div id="waitToast">⏳ يرجى الانتظار...</div>
    <div class="card">
        <div class="row"><input type="file" id="imageInput" accept="image/*" style="flex:1"></div>
        <div class="row">
            <button onclick="initSAM2()">🧠 SAM 2</button>
            <button onclick="clearOverlay()">🗑️ مسح</button>
            <button onclick="downloadResult()">💾 تحميل</button>
        </div>
    </div>
    <div id="loading">⚙️ جاري المعالجة...</div>
    <div id="result">
        <div style="position:relative;width:100%">
            <img id="mainImg" class="no-callout" oncontextmenu="return false;" draggable="false" style="width:100%;display:block;border-radius:8px;border:2px solid #444;touch-action:none">
            <canvas id="overlayCanvas" style="position:absolute;top:0;left:0;width:100%;height:100%;pointer-events:none;border-radius:8px"></canvas>
        </div>
        <div class="row" style="margin-top:8px">
            <button onclick="undoLast()">↩️ تراجع</button>
            <button id="toggleBtn" onclick="toggleView()">📸 الأصل</button>
            <button onclick="downloadResult()">💾 تحميل</button>
        </div>
    </div>
    <script>
    let magActive=false,magTimer=null,lastTX=0,lastTY=0,startTX=0,startTY=0,isScrolling=false,stepCount=0;
    function show(w){document.getElementById(w).style.display='block'}
    function hide(w){document.getElementById(w).style.display='none'}

    async function initSAM2(){
      const file=document.getElementById('imageInput').files[0];
      if(!file)return alert('اختر صورة أولاً');
      show('loading');document.getElementById('loading').textContent='🧠 جاري تحليل الصورة...';
      hide('result');stepCount=0;
      const fd=new FormData();fd.append('image',file);
      try{
        const r=await fetch('/init',{method:'POST',body:fd});const d=await r.json();
        if(d.error){alert(d.error);hide('loading');return}
        document.getElementById('mainImg').src='data:image/jpeg;base64,'+d.original;
        document.getElementById('mainImg').onload=function(){
          const ov=document.getElementById('overlayCanvas');
          ov.width=this.naturalWidth;ov.height=this.naturalHeight;
          ov.getContext('2d').clearRect(0,0,ov.width,ov.height);
          ov.style.display='block';
          document.getElementById('toggleBtn').textContent='📸 الأصل';
        };
        show('result');
        const img=document.getElementById('mainImg');
        img.addEventListener('touchstart',magStart,{passive:false});
        img.addEventListener('touchmove',magMove,{passive:false});
        img.addEventListener('touchend',magEnd);
        img.addEventListener('touchcancel',magCancel);
        img.addEventListener('mousedown',function(e){
          const r=img.getBoundingClientRect();
          submitClick(((e.clientX-r.left)/r.width)*100,((e.clientY-r.top)/r.height)*100);
        });
      }catch(e){alert('خطأ: '+e.message)}
      hide('loading')
    }

    function magStart(e){
      if(e.touches.length>1)return;
      startTX=e.touches[0].clientX;startTY=e.touches[0].clientY;
      lastTX=startTX;lastTY=startTY;isScrolling=false;
      if(magTimer)clearTimeout(magTimer);
      magTimer=setTimeout(function(){
        magTimer=null;
        if(!isScrolling){magActive=true;document.getElementById('magnifier').style.display='block';updateMag(lastTX,lastTY)}
      },350)
    }
    function magMove(e){
      if(e.touches.length>1){if(magTimer){clearTimeout(magTimer);magTimer=null}if(magActive){magActive=false;document.getElementById('magnifier').style.display='none'}return}
      lastTX=e.touches[0].clientX;lastTY=e.touches[0].clientY;
      if(magActive){if(e.cancelable)e.preventDefault();updateMag(lastTX,lastTY)}
      else if(magTimer&&(Math.abs(lastTX-startTX)>10||Math.abs(lastTY-startTY)>10)){isScrolling=true;clearTimeout(magTimer);magTimer=null}
    }
    function magEnd(e){
      if(magTimer){clearTimeout(magTimer);magTimer=null;return}
      if(!magActive)return;
      document.getElementById('magnifier').style.display='none';magActive=false;
      if(isScrolling)return;
      const img=document.getElementById('mainImg'),r=img.getBoundingClientRect(),t=e.changedTouches[0];
      const x=((t.clientX-r.left)/r.width)*100,y=((t.clientY-r.top)/r.height)*100;
      if(x<0||x>100||y<0||y>100)return;
      submitClick(x,y)
    }
    function magCancel(e){if(magTimer)clearTimeout(magTimer);magActive=false;isScrolling=false;document.getElementById('magnifier').style.display='none'}
    function updateMag(mx,my){
      const img=document.getElementById('mainImg'),r=img.getBoundingClientRect(),mag=document.getElementById('magnifier'),magImg=document.getElementById('magImg');
      let magX=mx-25,magY=my-130;
      if(magX<5)magX=5;if(magX>window.innerWidth-55)magX=window.innerWidth-55;
      if(magY<5)magY=my+50;
      mag.style.left=magX+'px';mag.style.top=magY+'px';
      magImg.src=img.src;magImg.style.width=(r.width*2.5)+'px';magImg.style.height=(r.height*2.5)+'px';
      magImg.style.left=(-(mx-r.left)*2.5+25)+'px';magImg.style.top=(-(my-r.top)*2.5+25)+'px'
    }

    async function submitClick(x,y){
      stepCount++;show('waitToast');
      const fd=new FormData();fd.append('image',document.getElementById('imageInput').files[0]);
      fd.append('x',x.toFixed(2));fd.append('y',y.toFixed(2));fd.append('step',stepCount);
      try{
        const r=await fetch('/click',{method:'POST',body:fd});const d=await r.json();
        if(d.error){alert(d.error);hide('waitToast');return}
        const ov=document.getElementById('overlayCanvas');ov.style.display='block';
        document.getElementById('toggleBtn').textContent='📸 الأصل';
        const img=new Image();img.onload=function(){ov.getContext('2d').drawImage(img,0,0)};
        img.src='data:image/png;base64,'+d.overlay;
      }catch(e){alert('خطأ: '+e.message)}
      hide('waitToast')
    }

    function toggleView(){
      const ov=document.getElementById('overlayCanvas'),btn=document.getElementById('toggleBtn');
      if(ov.style.display==='none'){ov.style.display='block';btn.textContent='📸 الأصل'}
      else{ov.style.display='none';btn.textContent='✏️ التعديل'}
    }
    function clearOverlay(){
      document.getElementById('overlayCanvas').getContext('2d').clearRect(0,0,
        document.getElementById('overlayCanvas').width,document.getElementById('overlayCanvas').height);
      stepCount=0;
    }
    async function undoLast(){
      if(stepCount<=0)return;stepCount--;show('waitToast');
      const fd=new FormData();fd.append('step',stepCount);
      try{
        const r=await fetch('/undo',{method:'POST',body:fd});const d=await r.json();
        if(d.error){alert(d.error);hide('waitToast');return}
        const ov=document.getElementById('overlayCanvas'),ctx=ov.getContext('2d');ctx.clearRect(0,0,ov.width,ov.height);
        if(d.overlay){const img=new Image();img.onload=function(){ctx.drawImage(img,0,0)};img.src='data:image/png;base64,'+d.overlay}
      }catch(e){alert('خطأ: '+e.message)}
      hide('waitToast')
    }
    function downloadResult(){
      const img=document.getElementById('mainImg');if(!img.src)return;
      const ov=document.getElementById('overlayCanvas'),c=document.createElement('canvas');
      c.width=ov.width;c.height=ov.height;const cx=c.getContext('2d');
      cx.drawImage(img,0,0,c.width,c.height);cx.drawImage(ov,0,0);
      const a=document.createElement('a');a.download='sam2_result.png';a.href=c.toDataURL('image/png');a.click()
    }
    </script>
</body>
</html>"""

def parse_multipart(parts, key):
    for p in parts:
        if f'name="{key}"'.encode() in p:
            i = p.find(b'\r\n\r\n')
            if i != -1:
                data = p[i+4:]
                if data.endswith(b'\r\n'): data = data[:-2]
                if data.endswith(b'--'): data = data[:-2]
                return data
    return None

def parse_text(parts, key, default=''):
    v = parse_multipart(parts, key)
    if v is None: return default
    try: return v.decode().strip()
    except: return default

overlay = None
overlay_step = 0

def process_init(img_bytes):
    global overlay, overlay_step
    arr = np.frombuffer(img_bytes, np.uint8)
    img = cv2.imdecode(arr, cv2.IMREAD_COLOR)
    if img is None: return None, "خطأ في قراءة الصورة"
    h, w = img.shape[:2]
    if w > 800:
        ratio = 800/w; img = cv2.resize(img, (800, int(h*ratio)))
    _, ob = cv2.imencode('.jpg', img, [cv2.IMWRITE_JPEG_QUALITY, 85])
    orig = base64.b64encode(ob).decode()
    predictor.set_image(cv2.cvtColor(img, cv2.COLOR_BGR2RGB))
    overlay = np.zeros((img.shape[0], img.shape[1], 4), dtype=np.uint8)
    overlay_step = 0
    return {'original': orig}, None

def process_click(img_bytes, cx, cy, step):
    global overlay, overlay_step
    arr = np.frombuffer(img_bytes, np.uint8)
    img = cv2.imdecode(arr, cv2.IMREAD_COLOR)
    if img is None: return None, "خطأ"
    h, w = img.shape[:2]
    if w > 800:
        ratio = 800/w; img = cv2.resize(img, (800, int(h*ratio)))
    
    # Get SAM 2 mask
    masks, scores, logits = predictor.predict(
        point_coords=np.array([[int(cx/100*img.shape[1]), int(cy/100*img.shape[0])]]),
        point_labels=np.array([1]),
        multimask_output=False,
    )
    mask = masks[0]; mu8 = (mask*255).astype(np.uint8)
    contours, _ = cv2.findContours(mu8, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
    cv2.drawContours(overlay, contours, -1, (255, 255, 255, 255), 2)
    overlay_step += 1
    # Save history
    cv2.imwrite(f'/tmp/sam2_hist_{overlay_step}.png', overlay)
    _, rb = cv2.imencode('.png', overlay)
    return {'overlay': base64.b64encode(rb).decode()}, None

def process_undo():
    global overlay, overlay_step
    if overlay_step <= 0: return None, "لا يوجد"
    overlay_step -= 1
    if overlay_step == 0:
        overlay = np.zeros((1,1,4), dtype=np.uint8)
        _, rb = cv2.imencode('.png', overlay)
        return {'overlay': base64.b64encode(rb).decode()}, None
    overlay = cv2.imread(f'/tmp/sam2_hist_{overlay_step}.png', cv2.IMREAD_UNCHANGED)
    _, rb = cv2.imencode('.png', overlay)
    return {'overlay': base64.b64encode(rb).decode()}, None

class Handler(BaseHTTPRequestHandler):
    def do_GET(self):
        self.send_response(200)
        self.send_header('Content-Type', 'text/html; charset=utf-8')
        self.end_headers()
        self.wfile.write(HTML_PAGE.encode('utf-8'))
    def do_POST(self):
        ct = self.headers.get('Content-Type', '')
        if not ct.startswith('multipart/form-data'): return self._json({'error':'نوع غير مدعوم'})
        cl = int(self.headers.get('Content-Length', 0))
        parts = self.rfile.read(cl).split(b'--' + ct.split('=')[1].encode())
        p = self.path
        if p == '/init':
            ib = parse_multipart(parts, 'image')
            if not ib: return self._json({'error':'لا توجد صورة'})
            r, e = process_init(ib)
            self._json({'error': e} if e else r)
        elif p == '/click':
            ib = parse_multipart(parts, 'image')
            cx = float(parse_text(parts, 'x', '50'))
            cy = float(parse_text(parts, 'y', '50'))
            st = int(parse_text(parts, 'step', '0'))
            if not ib: return self._json({'error':'لا توجد صورة'})
            r, e = process_click(ib, cx, cy, st)
            self._json({'error': e} if e else r)
        elif p == '/undo':
            r, e = process_undo()
            self._json({'error': e} if e else r)
    def _json(self, d):
        self.send_response(200)
        self.send_header('Content-Type', 'application/json; charset=utf-8')
        self.end_headers()
        self.wfile.write(json.dumps(d).encode('utf-8'))

if __name__ == '__main__':
    HTTPServer(('0.0.0.0', 8086), Handler).serve_forever()
