import { useEffect, useState, useRef, useCallback } from 'react';
import { useNavigate, useSearchParams } from 'react-router-dom';
import { ArrowRight, Upload, Crop, RotateCcw, RotateCw, FlipHorizontal2, FlipVertical2, Scissors, Crosshair, RefreshCw, Replace, Eye, Loader2, Check } from 'lucide-react';
import { base44 } from '@/api/base44Client';
import PageHeader from '@/components/app/PageHeader';
import CleanupControls from '@/components/studio/cleanup/CleanupControls';
import ConversionPreview from '@/components/studio/cleanup/ConversionPreview';
import { Image as ContentImage } from '@/components/ui/image';
import {
  DEFAULT_SETTINGS, loadImage, imageToCanvas, processImage, rotateCanvas, mirrorCanvas,
  cropCanvas, trimTransparent, canvasToBlob, canvasFromImageData
} from '@/lib/imageProcessing';
import { useExperienceMode } from '@/lib/ExperienceMode';
import { safeMediaUrl } from '@/lib/safeUrl';

const pipeline = [['Drawing', 'genuine'], ['Clean mask', 'genuine'], ['3D relief', 'preview'], ['Surface projection', 'preview']];

function settingsFromAsset(a) {
  const ps = a?.processingSettings || {};
  const s = { ...DEFAULT_SETTINGS, ...ps };
  if (a?.threshold != null) { s.thresholdEnabled = ps.thresholdEnabled ?? true; s.threshold = a.threshold; }
  if (a?.inverted != null) s.invert = !!a.inverted;
  if (a?.backgroundRemoved != null) s.removeWhiteBackground = !!a.backgroundRemoved;
  if (a?.smoothing != null) s.edgeSmoothing = a.smoothing;
  return s;
}

export default function SketchTo3D() {
  const [params] = useSearchParams();
  const projectId = params.get('project');
  const navigate = useNavigate();
  const { mode } = useExperienceMode();
  const guided = mode === 'guided';
  const [asset, setAsset] = useState(null);
  const [baseCanvas, setBaseCanvas] = useState(null);
  const [originalUrl, setOriginalUrl] = useState(null); // never-transformed upload
  const [settings, setSettings] = useState(DEFAULT_SETTINGS);
  const [processedUrl, setProcessedUrl] = useState(null);
  const [past, setPast] = useState([]);
  const [future, setFuture] = useState([]);
  const [emboss, setEmboss] = useState(1.2);
  const [depth, setDepth] = useState(0.8);
  const [inverted, setInverted] = useState(false);
  const [smoothing, setSmoothing] = useState(0.3);
  const [zoom, setZoom] = useState(1);
  const [pan, setPan] = useState({ x: 0, y: 0 });
  const [compare, setCompare] = useState(100);
  const [cropMode, setCropMode] = useState(false);
  const [cropRect, setCropRect] = useState(null);
  const [exporting, setExporting] = useState(false);
  const [savedMsg, setSavedMsg] = useState(false);
  const processedCanvasRef = useRef(null);
  const rafRef = useRef(null);
  const cropDrag = useRef(null);
  const imgWrapRef = useRef(null);
  const workerRef = useRef(null);
  const reqIdRef = useRef(0);

  // Load asset for project
  useEffect(() => {
    if (!projectId) return;
    let mounted = true;
    (async () => {
      const raw = await base44.entities.ArtworkAsset.filter({ projectId }).catch(() => []);
      const list = Array.isArray(raw) ? raw : [];
      if (!mounted || !list.length) return;
      const a = list[0];
      setAsset(a);
      setSettings(settingsFromAsset(a));
      setEmboss(a.processingSettings?.emboss ?? 1.2);
      setDepth(a.processingSettings?.depth ?? 0.8);
      setInverted(!!a.inverted);
      setSmoothing(a.smoothing ?? 0.3);
      const url = safeMediaUrl(a.originalFile);
      if (!url) return; // reject non-http(s)/relative schemes (e.g. javascript:) stored in records
      setOriginalUrl(url);
      const img = await loadImage(url);
      if (!mounted) return;
      const c = imageToCanvas(img);
      setBaseCanvas(c);
    })();
    return () => { mounted = false; };
  }, [projectId]);

  // Spin up the cleanup Web Worker once — offloads the heavy pixel pipeline off the main thread.
  useEffect(() => {
    try {
      workerRef.current = new Worker(new URL('../lib/cleanupWorker.js', import.meta.url), { type: 'module' });
    } catch { workerRef.current = null; /* fallback to synchronous processing below */ }
    return () => { if (workerRef.current) { workerRef.current.terminate(); workerRef.current = null; } };
  }, []);

  // Reprocess whenever base or settings change (non-destructive, debounced).
  // Runs on the Web Worker when available; falls back to the main thread otherwise.
  useEffect(() => {
    if (!baseCanvas) return;
    if (rafRef.current) cancelAnimationFrame(rafRef.current);
    rafRef.current = requestAnimationFrame(() => {
      const w = baseCanvas.width, h = baseCanvas.height;
      const worker = workerRef.current;
      if (!worker) {
        try {
          const c = processImage(baseCanvas, settings);
          processedCanvasRef.current = c;
          setProcessedUrl(c.toDataURL('image/png'));
        } catch { /* ignore transient processing errors */ }
        return;
      }
      const id = ++reqIdRef.current;
      const src = baseCanvas.getContext('2d').getImageData(0, 0, w, h);
      worker.onmessage = (e) => {
        const d = e.data || {};
        if (d.id !== id || d.error) return; // stale run superseded, or worker error
        try {
          const imgData = new ImageData(new Uint8ClampedArray(d.buffer), d.width, d.height);
          const c = canvasFromImageData(imgData);
          processedCanvasRef.current = c;
          setProcessedUrl(c.toDataURL('image/png'));
        } catch { /* ignore transient processing errors */ }
      };
      worker.postMessage({ id, width: w, height: h, buffer: src.data.buffer, settings }, [src.data.buffer]);
    });
    return () => { if (rafRef.current) cancelAnimationFrame(rafRef.current); };
  }, [baseCanvas, settings]);

  const snapshot = useCallback(() => ({
    base: baseCanvas ? baseCanvas.toDataURL('image/png') : null, settings: { ...settings }
  }), [baseCanvas, settings]);

  const beginInteraction = useCallback(() => {
    setPast(p => [...p.slice(-39), snapshot()]);
    setFuture([]);
  }, [snapshot]);

  const restore = async (snap) => {
    if (!snap) return;
    setSettings(snap.settings);
    if (snap.base) {
      const img = await loadImage(snap.base);
      setBaseCanvas(imageToCanvas(img, 4096));
    }
  };
  const undo = () => { if (!past.length) return; const last = past[past.length - 1]; setFuture(f => [snapshot(), ...f]); setPast(p => p.slice(0, -1)); restore(last); };
  const redo = () => { if (!future.length) return; const next = future[0]; setPast(p => [...p, snapshot()]); setFuture(f => f.slice(1)); restore(next); };

  const set = (patch) => setSettings(s => ({ ...s, ...patch }));

  const resetAll = () => {
    beginInteraction();
    setSettings(DEFAULT_SETTINGS);
    if (originalUrl) loadImage(originalUrl).then(img => setBaseCanvas(imageToCanvas(img)));
  };

  // geometric ops
  const rotate = (n) => { beginInteraction(); setBaseCanvas(c => rotateCanvas(c, n)); };
  const mirror = (axis) => { beginInteraction(); setBaseCanvas(c => mirrorCanvas(c, axis)); };
  const trim = () => { beginInteraction(); setBaseCanvas(c => trimTransparent(c)); };
  const applyCrop = () => {
    if (!cropRect || !imgWrapRef.current || !baseCanvas) { setCropMode(false); return; }
    const dispW = imgWrapRef.current.clientWidth;
    const scale = baseCanvas.width / dispW;
    beginInteraction();
    setBaseCanvas(c => cropCanvas(c, {
      x: cropRect.x * scale, y: cropRect.y * scale, w: cropRect.w * scale, h: cropRect.h * scale
    }));
    setCropRect(null); setCropMode(false);
  };

  const replaceImage = async (file) => {
    const { file_url } = await base44.integrations.Core.UploadFile({ file });
    const img = await loadImage(file_url);
    const dims = { w: img.naturalWidth, h: img.naturalHeight };
    const updated = await base44.entities.ArtworkAsset.update(asset.id, {
      originalFile: file_url, width: dims.w, height: dims.h,
      processedFile: null, processingSettings: {}, threshold: null, smoothing: null, inverted: false, backgroundRemoved: false
    });
    setAsset(updated); setOriginalUrl(file_url); setSettings(DEFAULT_SETTINGS);
    setBaseCanvas(imageToCanvas(img)); setPast([]); setFuture([]);
  };

  const exportPng = async () => {
    const c = processedCanvasRef.current;
    if (!c) return;
    setExporting(true);
    try {
      const blob = await canvasToBlob(c);
      const file = new File([blob], 'processed.png', { type: 'image/png' });
      const { file_url } = await base44.integrations.Core.UploadFile({ file });
      const updated = await base44.entities.ArtworkAsset.update(asset.id, {
        processedFile: file_url, processingSettings: settings, width: c.width, height: c.height,
        threshold: settings.thresholdEnabled ? settings.threshold : null,
        smoothing: settings.edgeSmoothing, inverted: settings.invert,
        backgroundRemoved: settings.removeWhiteBackground
      });
      setAsset(updated);
      setSavedMsg(true); setTimeout(() => setSavedMsg(false), 2500);
    } finally { setExporting(false); }
  };

  // crop drag on original
  const onCropDown = (e) => {
    if (!cropMode) return;
    const r = imgWrapRef.current.getBoundingClientRect();
    const x = e.clientX - r.left, y = e.clientY - r.top;
    cropDrag.current = { sx: x, sy: y }; setCropRect({ x, y, w: 0, h: 0 });
  };
  const onCropMove = (e) => {
    if (!cropMode || !cropDrag.current) return;
    const r = imgWrapRef.current.getBoundingClientRect();
    const x = Math.min(cropDrag.current.sx, e.clientX - r.left);
    const y = Math.min(cropDrag.current.sy, e.clientY - r.top);
    const w = Math.abs(e.clientX - r.left - cropDrag.current.sx);
    const h = Math.abs(e.clientY - r.top - cropDrag.current.sy);
    setCropRect({ x, y, w, h });
  };
  const onCropUp = () => { cropDrag.current = null; };

  return (
    <>
      <PageHeader eyebrow="Input · Sketch to 3D" title="Sketch to 3D" description="Clean the drawing with a genuine HTML-Canvas pixel pipeline, then preview how the mask is interpreted. Final printable geometry is produced by the external LimbForge Geometry Engine." />

      {!guided && (<div className="panel mb-5">
        <div className="flex flex-wrap items-center gap-2">
          {pipeline.map((p, i) => (
            <div key={p[0]} className="flex items-center gap-2">
              <span className={`inline-flex items-center gap-2 rounded-lg border px-3 py-1.5 text-xs font-medium ${p[1] === 'genuine' ? 'border-emerald-400/30 bg-emerald-400/10 text-emerald-200' : 'border-cyan-400/30 bg-cyan-400/10 text-cyan-200'}`}>
                {p[0]}<span className="text-[9px] uppercase opacity-80">{p[1]}</span>
              </span>
              {i < pipeline.length - 1 && <ArrowRight size={13} className="text-slate-600" />}
            </div>
          ))}
        </div>
      </div>)}

      {!asset && (
        <section className="panel mb-5">
          <label className="block cursor-pointer rounded-lg border border-dashed border-white/15 bg-white/[0.02] p-6 text-center text-sm text-slate-400 transition hover:border-cyan-400/40 hover:text-cyan-200">
            <Upload size={18} className="mr-2 inline" />Upload a drawing to begin the cleanup pipeline
            <input type="file" accept="image/*" className="hidden" onChange={async (e) => {
              const f = e.target.files[0]; if (!f || !projectId) return;
              const { file_url } = await base44.integrations.Core.UploadFile({ file: f });
              const img = await loadImage(file_url);
              const a = await base44.entities.ArtworkAsset.create({ projectId, originalFile: file_url, width: img.naturalWidth, height: img.naturalHeight, processingSettings: {} });
              setAsset(a); setOriginalUrl(file_url); setBaseCanvas(imageToCanvas(img));
            }} />
          </label>
        </section>
      )}

      {asset && (
        <div className="grid gap-4 xl:grid-cols-3">
          {/* LEFT — original artwork + geometric tools */}
          <section className="panel">
            <h2 className="section-title">Original artwork</h2>
            <div ref={imgWrapRef} className="checkerboard relative grid h-60 place-items-center overflow-hidden rounded-xl border border-white/[0.07]"
              onMouseDown={onCropDown} onMouseMove={onCropMove} onMouseUp={onCropUp} onMouseLeave={onCropUp}
              style={{ cursor: cropMode ? 'crosshair' : 'default' }}>
              {baseCanvas ? (
                <img src={baseCanvas.toDataURL('image/png')} alt="Original" className="max-h-full max-w-full object-contain select-none pointer-events-none" draggable={false} />
              ) : <div className="empty">No drawing uploaded.</div>}
              {cropMode && cropRect && (
                <div className="absolute border-2 border-cyan-400 bg-cyan-400/10" style={{ left: cropRect.x, top: cropRect.y, width: cropRect.w, height: cropRect.h }} />
              )}
            </div>
            <div className="mt-3 flex flex-wrap gap-1.5">
              <button onClick={() => setCropMode(c => !c)} className={`tool-button ${cropMode ? 'active-tool' : ''}`}><Crop size={13} />{cropMode ? 'Crop mode' : 'Crop'}</button>
              {cropMode && <button onClick={applyCrop} className="btn-primary !min-h-9 px-3 text-xs"><Scissors size={13} />Apply crop</button>}
              <button onClick={() => rotate(-1)} className="tool-button"><RotateCcw size={13} />Rotate</button>
              <button onClick={() => rotate(1)} className="tool-button"><RotateCw size={13} /></button>
              <button onClick={() => mirror('h')} className="tool-button"><FlipHorizontal2 size={13} /></button>
              <button onClick={() => mirror('v')} className="tool-button"><FlipVertical2 size={13} /></button>
              <button onClick={trim} className="tool-button" title="Trim transparent padding"><Crosshair size={13} />Trim</button>
              <label className="tool-button cursor-pointer"><Replace size={13} />Replace<input type="file" accept="image/*" className="hidden" onChange={e => { const f = e.target.files[0]; if (f) replaceImage(f); }} /></label>
            </div>
            <p className="mt-3 text-[11px] text-slate-500">Geometric transforms edit the source image. Use Undo/Redo in the centre panel to revert.</p>
          </section>

          {/* CENTRE — processed mask */}
          <section className="panel">
            <div className="flex items-center justify-between">
              <h2 className="section-title !mb-0">Cleaned mask</h2>
              <div className="flex items-center gap-1.5 text-[11px] text-slate-400">
                <button onClick={() => setZoom(z => Math.max(0.5, +(z - 0.25).toFixed(2)))} className="tool-rail-btn h-7 w-7 text-xs">−</button>
                <span className="mono w-10 text-center">{Math.round(zoom * 100)}%</span>
                <button onClick={() => setZoom(z => Math.min(4, +(z + 0.25).toFixed(2)))} className="tool-rail-btn h-7 w-7 text-xs">+</button>
                <button onClick={() => { setZoom(1); setPan({ x: 0, y: 0 }); }} className="tool-rail-btn h-7 w-7 text-xs" title="Reset view"><RefreshCw size={12} /></button>
              </div>
            </div>
            <div className="checkerboard relative grid h-60 place-items-center overflow-hidden rounded-xl border border-white/[0.07]"
              onWheel={e => { if (e.ctrlKey) { e.preventDefault(); setZoom(z => Math.max(0.5, Math.min(4, +(z - e.deltaY * 0.002).toFixed(2)))); } }}
              onMouseDown={e => { const r = e.currentTarget.getBoundingClientRect(); const s = { x: e.clientX - r.left - pan.x, y: e.clientY - r.top - pan.y }; const mv = (ev) => { const rr = e.currentTarget.getBoundingClientRect(); setPan({ x: ev.clientX - rr.left - s.x, y: ev.clientY - rr.top - s.y }); }; const up = () => { window.removeEventListener('mousemove', mv); window.removeEventListener('mouseup', up); }; window.addEventListener('mousemove', mv); window.addEventListener('mouseup', up); }}
              style={{ cursor: 'grab' }}>
              <div className="relative" style={{ transform: `translate(${pan.x}px, ${pan.y}px) scale(${zoom})`, transformOrigin: 'center', transition: 'none' }}>
                {processedUrl
                  ? <img src={processedUrl} alt="Processed mask" className="max-h-60 max-w-full object-contain select-none pointer-events-none" draggable={false} />
                  : <div className="empty">Processing…</div>}
                {/* before/after compare: original revealed up to slider position */}
                {baseCanvas && (
                  <img src={baseCanvas.toDataURL('image/png')} alt="Original overlay" className="absolute inset-0 m-auto max-h-60 max-w-full object-contain pointer-events-none"
                    style={{ clipPath: `inset(0 ${100 - compare}% 0 0) opacity-60` }} draggable={false} />
                )}
              </div>
            </div>
            <div className="mt-2 flex items-center gap-2 text-[11px] text-slate-400">
              <Eye size={12} />Before / after
              <input type="range" min={0} max={100} value={compare} onChange={e => setCompare(Number(e.target.value))} className="flex-1 accent-cyan-400" />
              <span className="mono">{compare}%</span>
            </div>
            <div className="mt-3 border-t border-white/[0.05] pt-3">
              <CleanupControls s={settings} set={set} beginInteraction={beginInteraction} onUndo={undo} onRedo={redo} onResetAll={resetAll}
                onExport={exportPng} canUndo={past.length > 0} canRedo={future.length > 0} exporting={exporting} />
            </div>
            {savedMsg && <div className="mt-2 flex items-center gap-1.5 text-[11px] text-emerald-300"><Check size={13} />Processed PNG saved — now used by the 3D Studio.</div>}
          </section>

          {/* RIGHT — 3D interpretation preview */}
          <section className="panel">
            <h2 className="section-title">3D input preview</h2>
            <ConversionPreview processedUrl={processedUrl} emboss={emboss} depth={depth} inverted={inverted} smoothing={smoothing} />
            <div className="mt-4 grid grid-cols-2 gap-3 border-t border-white/[0.05] pt-3">
              <label className="form-label">Emboss height<span className="mono text-slate-200">{emboss.toFixed(1)} mm</span><input type="range" min={0.4} max={4} step={0.1} value={emboss} onChange={e => setEmboss(Number(e.target.value))} className="w-full accent-cyan-400" /></label>
              <label className="form-label">Engraving depth<span className="mono text-slate-200">{depth.toFixed(1)} mm</span><input type="range" min={0.2} max={3} step={0.1} value={depth} onChange={e => setDepth(Number(e.target.value))} className="w-full accent-cyan-400" /></label>
              <label className="form-label">Smoothing<span className="mono text-slate-200">{smoothing.toFixed(2)}</span><input type="range" min={0} max={1} step={0.05} value={smoothing} onChange={e => setSmoothing(Number(e.target.value))} className="w-full accent-cyan-400" /></label>
              <label className="flex items-center gap-2 text-sm text-slate-300"><input type="checkbox" checked={inverted} onChange={e => setInverted(e.target.checked)} className="h-4 w-4 accent-cyan-400" />Invert mask</label>
            </div>
          </section>
        </div>
      )}

      <div className="mt-6 flex justify-end">
        <button onClick={async () => { if (projectId) { await base44.entities.CoverCanvasProject.update(projectId, { status: 'studio' }); navigate(`/studio?project=${projectId}`); } }} disabled={!asset} className="btn-primary">Open 3D Studio<ArrowRight size={18} /></button>
      </div>
    </>
  );
}