import { useEffect, useState, useRef } from 'react';
import { useNavigate, useSearchParams } from 'react-router-dom';
import { Panel, PanelGroup, PanelResizeHandle } from 'react-resizable-panels';
import { ArrowRight, Check } from 'lucide-react';
import { base44 } from '@/api/base44Client';
import PageHeader from '@/components/app/PageHeader';
import CoverViewer from '@/components/studio/CoverViewer';
import ArtworkToolsPanel from '@/components/studio/ArtworkToolsPanel';
import StudioRightPanel from '@/components/studio/StudioRightPanel';
import ErrorBoundary from '@/components/ErrorBoundary';
import ViewerErrorBoundary from '@/components/studio/ViewerErrorBoundary';
import GuidedStudio from '@/components/studio/GuidedStudio';
import { useExperienceMode } from '@/lib/ExperienceMode';

function PanelError({ error, retry, label }) {
  return (
    <div className="grid h-full place-items-center rounded-2xl border border-white/[0.06] bg-[#0d1117] p-6 text-center">
      <div>
        <p className="text-sm font-medium text-amber-200">{label || 'Panel'} could not load.</p>
        <button onClick={retry} className="btn-secondary mt-3 text-xs">Retry</button>
        {import.meta.env?.DEV && (
          <pre className="mt-2 max-h-32 overflow-auto rounded border border-white/10 bg-black/40 p-2 text-left text-[10px] text-red-300">{String(error)}</pre>
        )}
      </div>
    </div>
  );
}

const VIEW_MODES = [
  ['studio', 'Studio'], ['wireframe', 'Wireframe'], ['geometry', 'Geometry'],
  ['protected', 'Protected Zones'], ['decoration', 'Decoration Zones'], ['connector', 'Connector Clearance'], ['print', 'Print Preview']
];

export default function Studio() {
  const [params] = useSearchParams();
  const projectId = params.get('project');
  const navigate = useNavigate();
  const [layers, setLayers] = useState([]);
  const [selected, setSelected] = useState(null);
  const [project, setProject] = useState(null);
  const [cover, setCover] = useState(null);
  const [assets, setAssets] = useState([]);
  const [viewMode, setViewMode] = useState('studio');
  const [protectedVisible, setProtectedVisible] = useState([]);
  const [lockAspect, setLockAspect] = useState(false);
  const [desktop, setDesktop] = useState(typeof window !== 'undefined' && window.innerWidth >= 1024);
  const [loadError, setLoadError] = useState(null);
  const [opError, setOpError] = useState(null);
  const [savedAt, setSavedAt] = useState(null);
  const { mode } = useExperienceMode();
  const guided = mode === 'guided';
  const layersRef = useRef([]);
  useEffect(() => { layersRef.current = layers; }, [layers]);

  // Image dimensions with a guaranteed-settling promise (onerror fallback so
  // it never stays pending forever).
  const loadImageDims = (url) => new Promise((res) => {
    const img = new Image();
    img.onload = () => res({ w: img.naturalWidth, h: img.naturalHeight });
    img.onerror = () => res({ w: 1024, h: 1024 });
    img.src = url;
  });

  // Development logging: route, project/cover query status, layer count, selection.
  useEffect(() => {
    if (!import.meta.env?.DEV) return;
    // eslint-disable-next-line no-console
    console.log('[Studio] route /studio', { projectId });
  }, [projectId]);
  useEffect(() => {
    if (!import.meta.env?.DEV) return;
    // eslint-disable-next-line no-console
    console.log('[Studio] state', { project: project?.id ?? null, cover: cover?.id ?? null, layerCount: layers.length, selectedLayer: selected?.id ?? null });
  }, [project, cover, layers.length, selected]);

  // Live (local-only) transform during handle drag; persisted on commit.
  const liveUpdate = (layer, patch) => {
    setLayers(ls => ls.map(x => x.id === layer.id ? { ...x, ...patch } : x));
    if (selected?.id === layer.id) setSelected(s => s ? { ...s, ...patch } : s);
  };
  const commitTransform = async (layer) => {
    const latest = (Array.isArray(layersRef.current) ? layersRef.current : []).find(x => x.id === layer.id) || layer;
    try {
      await update(latest, {
        positionX: Number(latest.positionX) || 0, positionY: Number(latest.positionY) || 0,
        scaleX: Number(latest.scaleX) || 1, scaleY: Number(latest.scaleY) || 1, rotation: Number(latest.rotation) || 0
      });
    } catch { /* update() already surfaces a friendly error */ }
  };

  // Apply a PromptForge concept: create ArtworkAsset + ArtworkLayer, select it.
  const applyConcept = async (concept) => {
    const url = concept?.previewImageUrl;
    if (!url || !projectId) { setOpError('Could not apply concept — missing image or project.'); return null; }
    try {
      setOpError(null);
      const dims = await loadImageDims(url);
      const a = await base44.entities.ArtworkAsset.create({
        projectId, originalFile: url, processedFile: url, width: dims.w, height: dims.h,
        processingSettings: { conceptId: concept.id, colourPalette: concept.colourPalette }, backgroundRemoved: false
      });
      setAssets(xs => [...(Array.isArray(xs) ? xs : []), a]);
      const mode = concept.applicationModeSuggestion || 'colour_texture';
      const l = await base44.entities.ArtworkLayer.create({
        projectId, artworkAssetId: a.id, name: concept.title || 'Concept layer', order: (Array.isArray(layers) ? layers : []).length,
        visible: true, locked: false, positionX: 0, positionY: 0, scaleX: 1, scaleY: 1, rotation: 0, mirrored: false,
        projectionMode: 'planar', embossHeight: mode === 'raised_emboss' ? 1.2 : 1, engravingDepth: mode === 'engraving' ? 0.8 : 0.5,
        opacity: 1
      });
      setLayers(ls => [...(Array.isArray(ls) ? ls : []), l]); setSelected(l);
      if (mode) await updateProject({ applicationMode: mode });
      markSaved();
      return l;
    } catch (e) {
      setOpError(`Could not apply concept to cover. ${e?.message || ''}`);
      return null;
    }
  };

  // Keyboard fine movement for the selected, visible, unlocked layer.
  useEffect(() => {
    const onKey = (e) => {
      if (!selected || selected.locked || !selected.visible) return;
      const tag = (e.target.tagName || '').toLowerCase();
      if (tag === 'input' || tag === 'textarea' || tag === 'select') return;
      const step = e.shiftKey ? 0.1 : 0.01;
      let patch = null;
      if (e.key === 'ArrowLeft') patch = { positionX: (selected.positionX || 0) - step };
      else if (e.key === 'ArrowRight') patch = { positionX: (selected.positionX || 0) + step };
      else if (e.key === 'ArrowUp') patch = { positionY: (selected.positionY || 0) + step };
      else if (e.key === 'ArrowDown') patch = { positionY: (selected.positionY || 0) - step };
      if (!patch) return;
      e.preventDefault();
      liveUpdate(selected, patch);
      commitTransform({ ...selected, ...patch });
    };
    window.addEventListener('keydown', onKey);
    return () => window.removeEventListener('keydown', onKey);
  }, [selected]);

  useEffect(() => {
    const f = () => setDesktop(window.innerWidth >= 1024);
    window.addEventListener('resize', f);
    return () => window.removeEventListener('resize', f);
  }, []);

  useEffect(() => {
    if (!projectId) {
      setLayers([]); setSelected(null); setProject(null); setCover(null); setAssets([]); setLoadError(null);
      return;
    }
    let alive = true;
    Promise.all([
      base44.entities.ArtworkLayer.filter({ projectId }, 'order').catch(() => []),
      base44.entities.CoverCanvasProject.get(projectId).catch(() => null),
      base44.entities.ArtworkAsset.filter({ projectId }).catch(() => [])
    ]).then(async ([x, p, a]) => {
      if (!alive) return;
      const safeLayers = Array.isArray(x) ? x : [];
      const safeAssets = Array.isArray(a) ? a : [];
      setLayers(safeLayers);
      setSelected(safeLayers[0] ?? null);
      setProject(p ?? null);
      setAssets(safeAssets);
      setLoadError(null);
      if (p?.coverModelId) {
        try { setCover(await base44.entities.CoverModel.get(p.coverModelId)); }
        catch { setCover(null); }
      } else {
        setCover(null);
      }
    }).catch(() => {
      if (!alive) return;
      setLayers([]); setSelected(null); setProject(null); setCover(null); setAssets([]);
      setLoadError('Could not load this project. Check your connection and try again.');
    });
    return () => { alive = false; };
  }, [projectId]);

  const safeLayers = Array.isArray(layers) ? layers : [];
  const safeAssets = Array.isArray(assets) ? assets : [];

  const assetFor = (l) => safeAssets.find(a => a.id === l?.artworkAssetId);

  const markSaved = () => {
    setSavedAt(new Date());
    if (projectId) base44.entities.CoverCanvasProject.update(projectId, { lastSavedAt: new Date().toISOString(), hasUnsavedChanges: false }).catch(() => {});
  };
  const update = async (layer, changes) => {
    if (!layer) return;
    try {
      const saved = await base44.entities.ArtworkLayer.update(layer.id, changes);
      setLayers(ls => (Array.isArray(ls) ? ls : []).map(x => x.id === saved.id ? saved : x).sort((a, b) => (a.order ?? 0) - (b.order ?? 0)));
      if (selected?.id === saved.id) setSelected(saved);
      markSaved();
    } catch (e) { setOpError(`Could not update layer. ${e?.message || ''}`); }
  };
  const updateProject = async (changes) => {
    if (!projectId) return;
    try { const p = await base44.entities.CoverCanvasProject.update(projectId, changes); setProject(p); }
    catch (e) { setOpError(`Could not update project. ${e?.message || ''}`); }
  };
  const updateAsset = async (asset, changes) => {
    if (!asset) return;
    try { const a = await base44.entities.ArtworkAsset.update(asset.id, changes); setAssets(xs => (Array.isArray(xs) ? xs : []).map(x => x.id === a.id ? a : x)); }
    catch (e) { setOpError(`Could not update artwork. ${e?.message || ''}`); }
  };
  const move = async (layer, delta) => {
    const idx = safeLayers.findIndex(x => x.id === layer.id);
    const other = safeLayers[idx + delta];
    if (!other) return;
    await Promise.all([update(layer, { order: other.order }), update(other, { order: layer.order })]);
  };
  const duplicate = async (layer) => {
    if (!layer) return;
    try {
      const { id, ...rest } = layer;
      const copy = await base44.entities.ArtworkLayer.create({ ...rest, projectId, name: `${layer.name} copy`, order: (layer.order ?? 0) + 1 });
      setLayers(ls => [...(Array.isArray(ls) ? ls : []), copy].sort((a, b) => (a.order ?? 0) - (b.order ?? 0)));
    } catch (e) { setOpError(`Could not duplicate layer. ${e?.message || ''}`); }
  };
  const deleteLayer = async (layer) => {
    if (!layer) return;
    try {
      await base44.entities.ArtworkLayer.delete(layer.id);
      setLayers(ls => (Array.isArray(ls) ? ls : []).filter(x => x.id !== layer.id));
      if (selected?.id === layer.id) setSelected(null);
    } catch (e) { setOpError(`Could not delete layer. ${e?.message || ''}`); }
  };
  const addLayer = async () => {
    try {
      const l = await base44.entities.ArtworkLayer.create({
        projectId, artworkAssetId: safeLayers[0]?.artworkAssetId || '', name: `Layer ${safeLayers.length + 1}`, order: safeLayers.length,
        visible: true, locked: false, positionX: 0, positionY: 0, scaleX: 1, scaleY: 1, rotation: 0, mirrored: false,
        projectionMode: 'planar', embossHeight: 1, engravingDepth: 0.5, opacity: 1
      });
      setLayers(ls => [...(Array.isArray(ls) ? ls : []), l]); setSelected(l); markSaved();
    } catch (e) { setOpError(`Could not add layer. ${e?.message || ''}`); }
  };
  const uploadArtwork = async (file) => {
    if (!file || !projectId) return;
    try {
      setOpError(null);
      const { file_url } = await base44.integrations.Core.UploadFile({ file });
      const dims = await loadImageDims(file_url);
      const a = await base44.entities.ArtworkAsset.create({ projectId, originalFile: file_url, width: dims.w, height: dims.h, processingSettings: {} });
      setAssets(xs => [...(Array.isArray(xs) ? xs : []), a]);
      const l = await base44.entities.ArtworkLayer.create({ projectId, artworkAssetId: a.id, name: file.name.replace(/\.[^.]+$/, ''), order: safeLayers.length, visible: true, locked: false, positionX: 0, positionY: 0, scaleX: 1, scaleY: 1, rotation: 0, mirrored: false, projectionMode: 'planar', opacity: 1, embossHeight: 1, engravingDepth: 0.5 });
      setLayers(ls => [...(Array.isArray(ls) ? ls : []), l]); setSelected(l); markSaved();
    } catch (e) { setOpError(`Could not upload artwork. ${e?.message || ''}`); }
  };
  const replaceArtwork = async (file) => {
    if (!selected || !file) return;
    const a = assetFor(selected);
    if (!a) return uploadArtwork(file);
    try {
      const { file_url } = await base44.integrations.Core.UploadFile({ file });
      const dims = await loadImageDims(file_url);
      await updateAsset(a, { originalFile: file_url, width: dims.w, height: dims.h });
    } catch (e) { setOpError(`Could not replace artwork. ${e?.message || ''}`); }
  };
  const toggleProtected = (i) => setProtectedVisible(s => s.includes(i) ? s.filter(x => x !== i) : [...s, i]);

  const tools = (
    <ErrorBoundary label="Artwork tools" fallback={(p) => <PanelError {...p} label="Artwork tools" />}>
      <ArtworkToolsPanel
        project={project} selected={selected} asset={assetFor(selected)}
        onUpdateLayer={update} onUpdateProject={updateProject} onUpdateAsset={updateAsset}
        onUpload={uploadArtwork} onReplace={replaceArtwork} onRemove={() => deleteLayer(selected)}
        onDuplicate={duplicate} onMove={move} onDelete={deleteLayer}
        onNavigate={(r) => navigate(r + (projectId ? `?project=${projectId}` : ''))}
        projectId={projectId} onApplyConcept={applyConcept}
        onOpenFull={() => navigate(`/promptforge${projectId ? `?project=${projectId}` : ''}`)}
        lockAspect={lockAspect} onSetLockAspect={setLockAspect}
      />
    </ErrorBoundary>
  );
  const viewport = (
    <ViewerErrorBoundary>
      <CoverViewer
        cover={cover} mode={viewMode} onModeChange={setViewMode} modes={VIEW_MODES} visibleProtected={protectedVisible}
        layers={layers} assets={assets} selected={selected}
        lockAspect={lockAspect}
        onLiveTransform={liveUpdate} onCommitTransform={commitTransform} onSelectLayer={setSelected}
      />
    </ViewerErrorBoundary>
  );
  const right = (
    <ErrorBoundary label="Studio right" fallback={(p) => <PanelError {...p} label="Studio right" />}>
      <StudioRightPanel
        project={project} cover={cover} layers={layers} selected={selected} assets={assets}
        onSelect={setSelected} onUpdateLayer={update} onMove={move} onDuplicate={duplicate} onDelete={deleteLayer} onAddLayer={addLayer}
        protectedVisible={protectedVisible} onToggleProtected={toggleProtected}
        onNavigate={(r) => navigate(r + (projectId ? `?project=${projectId}` : ''))}
      />
    </ErrorBoundary>
  );

  return (
    <>
      <PageHeader eyebrow="Canvas · 3D Studio" title="Cover studio" description="Direct artwork placement over the prosthetic cover. Geometry treatments marked simulation require the live LimbForge Geometry Engine." />
      <div className="mb-3 flex items-center gap-3 text-xs">
        {savedAt && <span className="inline-flex items-center gap-1 text-emerald-300"><Check size={13} />Draft saved</span>}
        {project?.hasUnsavedChanges && <span className="text-amber-300">Unsaved changes from a previous session recovered.</span>}
      </div>
      {(loadError || opError) && (
        <div className="warning-box mb-4 flex items-center justify-between">
          <span>{loadError || opError}</span>
          <button onClick={() => { setLoadError(null); setOpError(null); }} className="ml-3 underline">Dismiss</button>
        </div>
      )}
      {guided ? (
        <GuidedStudio
          project={project} cover={cover} layers={layers} selected={selected} assets={assets} setSelected={setSelected}
          liveUpdate={liveUpdate} commitTransform={commitTransform} update={update} updateProject={updateProject} updateAsset={updateAsset}
          duplicate={duplicate} deleteLayer={deleteLayer} move={move} addLayer={addLayer} uploadArtwork={uploadArtwork} replaceArtwork={replaceArtwork} assetFor={assetFor}
          viewMode={viewMode} setViewMode={setViewMode} modes={VIEW_MODES} protectedVisible={protectedVisible} toggleProtected={toggleProtected} lockAspect={lockAspect} setLockAspect={setLockAspect}
          navigate={navigate} opError={opError} setOpError={setOpError} applyConcept={applyConcept}
        />
      ) : (
        <>
          <div className="h-[calc(100vh-176px)] min-h-[540px]">
            {desktop ? (
              <PanelGroup direction="horizontal" className="h-full gap-3">
                <Panel defaultSize={22} minSize={18} maxSize={34}>{tools}</Panel>
                <PanelResizeHandle className="w-1.5 shrink-0 cursor-col-resize rounded bg-white/[0.05] transition hover:bg-cyan-400/40" />
                <Panel minSize={40}><div className="h-full">{viewport}</div></Panel>
                <PanelResizeHandle className="w-1.5 shrink-0 cursor-col-resize rounded bg-white/[0.05] transition hover:bg-cyan-400/40" />
                <Panel defaultSize={26} minSize={20} maxSize={38}>{right}</Panel>
              </PanelGroup>
            ) : (
              <div className="flex h-full flex-col gap-3 overflow-y-auto">
                <div className="h-[42vh] shrink-0">{tools}</div>
                <div className="h-[58vh] shrink-0">{viewport}</div>
                <div className="h-[60vh] shrink-0">{right}</div>
              </div>
            )}
          </div>
          <div className="mt-4 flex justify-end">
            <button onClick={async () => { if (projectId) { await updateProject({ status: 'validation' }); navigate(`/validation?project=${projectId}`); } }} className="btn-primary">Validate & process<ArrowRight size={17} /></button>
          </div>
        </>
      )}
    </>
  );
}