// Reconsolidation — a synaptic pattern that demolishes and rebuilds, drifting each recall.
// "demolished and rebuilt. every time. in the present."
const { useState, useEffect, useRef, useMemo } = React;

const reconStyles = {
  wrap: {
    display: 'grid', gridTemplateColumns: 'minmax(0, 1fr) 280px',
    gap: 36, alignItems: 'stretch',
  },
  canvas: {
    position: 'relative',
    aspectRatio: '4 / 3',
    background: 'radial-gradient(ellipse at 50% 50%, rgba(207,191,149,0.10), transparent 70%), rgba(38,39,39,0.4)',
    borderRadius: 12,
    border: '1px solid var(--border)',
    overflow: 'hidden',
  },
  panel: {
    display: 'flex', flexDirection: 'column', gap: 18,
    padding: 24,
    background: 'rgba(246,240,226,0.02)',
    border: '1px solid var(--border)',
    borderRadius: 12,
  },
  state: {
    fontFamily: 'var(--font-ui)',
    fontSize: 10, letterSpacing: '0.32em', textTransform: 'uppercase',
    color: 'var(--glow)',
  },
  stateText: {
    fontFamily: 'var(--font-display)', fontSize: 32, lineHeight: 1, fontWeight: 600,
    color: 'var(--fg)', letterSpacing: '-0.02em', margin: 0,
  },
  desc: {
    fontFamily: 'var(--font-prose)', fontSize: 13, lineHeight: 1.65,
    color: 'var(--fg-soft)', margin: 0, minHeight: 86,
  },
  meta: {
    display: 'flex', justifyContent: 'space-between',
    fontFamily: 'var(--font-ui)', fontSize: 10, letterSpacing: '0.18em',
    textTransform: 'uppercase', color: 'var(--muted)',
    marginTop: 'auto', paddingTop: 14, borderTop: '1px solid var(--border)',
  },
  metaVal: { color: 'var(--glow)' },
  drift: {
    fontFamily: 'var(--font-ui)', fontSize: 11, color: 'var(--fg-soft)',
    display: 'flex', flexDirection: 'column', gap: 6,
  },
  driftBar: {
    height: 4, background: 'rgba(207,191,149,0.12)',
    borderRadius: 4, overflow: 'hidden', position: 'relative',
  },
  driftFill: {
    position: 'absolute', left: 0, top: 0, bottom: 0,
    background: 'linear-gradient(90deg, var(--glow-soft), var(--glow))',
    transition: 'width 600ms cubic-bezier(0.4,0,0.2,1)',
  },
  windowBar: {
    height: 2, background: 'rgba(207,191,149,0.10)',
    borderRadius: 2, overflow: 'hidden', position: 'relative',
  },
  windowFill: {
    position: 'absolute', left: 0, top: 0, bottom: 0,
    background: 'var(--glow)',
    boxShadow: '0 0 8px var(--glow)',
  },
};

// initial node positions form a recognizable, intentional shape (a "memory")
// we use a heart-ish constellation
const ANCHOR_NODES = [
  [0.50, 0.28], [0.40, 0.22], [0.32, 0.26], [0.28, 0.36], [0.30, 0.48], [0.40, 0.60],
  [0.50, 0.72], [0.60, 0.60], [0.70, 0.48], [0.72, 0.36], [0.68, 0.26], [0.60, 0.22],
  // internal
  [0.42, 0.40], [0.50, 0.45], [0.58, 0.40], [0.50, 0.55],
];
const NODE_EDGES = [
  [0,1],[1,2],[2,3],[3,4],[4,5],[5,6],[6,7],[7,8],[8,9],[9,10],[10,11],[11,0],
  [12,13],[13,14],[14,12],[13,15],
  [1,12],[5,15],[8,14],[10,12],
];

function Reconsolidation() {
  // each node has an offset accumulated over rebuilds, and a current rendered position
  const [phase, setPhase] = useState('stable'); // stable | dismantling | labile | rebuilding | complete
  const [recallCount, setRecallCount] = useState(0);
  const [labileT, setLabileT] = useState(0); // 0..1 progress through labile window
  const [drift, setDrift] = useState(0); // accumulated drift 0..1
  const [autoMode, setAutoMode] = useState(false);

  // node positions, kept in state so we can mutate per cycle
  const [nodes, setNodes] = useState(() => ANCHOR_NODES.map(([x,y]) => ({ x, y, ax: x, ay: y })));
  const [particles, setParticles] = useState([]); // floating proteins during labile

  const recall = () => {
    if (phase !== 'stable' && phase !== 'complete') return;
    if (phase === 'complete') return;
    setPhase('dismantling');
    // spawn particles
    setParticles(nodes.flatMap((n, i) => Array.from({length: 4}).map((_, k) => ({
      id: `${recallCount}-${i}-${k}-${Math.random()}`,
      x: n.x, y: n.y,
      vx: (Math.random()-0.5) * 0.6,
      vy: (Math.random()-0.5) * 0.6 - 0.05,
      life: 0.7 + Math.random() * 0.4,
    }))));
    setTimeout(() => {
      setPhase('labile');
      setLabileT(0);
    }, 900);
  };

  // labile window timing
  useEffect(() => {
    if (phase !== 'labile') return;
    const dur = 2400;
    const start = performance.now();
    let raf;
    const tick = (now) => {
      const t = Math.min(1, (now - start) / dur);
      setLabileT(t);
      if (t < 1) raf = requestAnimationFrame(tick);
      else {
        setPhase('rebuilding');
      }
    };
    raf = requestAnimationFrame(tick);
    return () => cancelAnimationFrame(raf);
  }, [phase]);

  // particle drift during labile
  useEffect(() => {
    if (phase !== 'labile' && phase !== 'dismantling') return;
    let raf;
    const tick = () => {
      setParticles(ps => ps
        .map(p => ({ ...p, x: p.x + p.vx * 0.004, y: p.y + p.vy * 0.004, life: p.life - 0.006 }))
        .filter(p => p.life > 0)
      );
      raf = requestAnimationFrame(tick);
    };
    raf = requestAnimationFrame(tick);
    return () => cancelAnimationFrame(raf);
  }, [phase]);

  // rebuild — slightly drifted
  useEffect(() => {
    if (phase !== 'rebuilding') return;
    // bigger increment per cycle so 6 recalls reaches ~100%
    const newDrift = Math.min(1, drift + 0.16 + Math.random() * 0.04);
    setDrift(newDrift);
    // perturb each node from its anchor; positions drift more each rebuild
    const perturb = newDrift * 0.10; // up to ~10% of canvas
    setNodes(prev => prev.map(n => ({
      ...n,
      x: n.ax + (Math.random() - 0.5) * perturb * 2,
      y: n.ay + (Math.random() - 0.5) * perturb * 2,
    })));
    setRecallCount(c => c + 1);
    setParticles([]);
    setTimeout(() => {
      if (newDrift >= 0.999) setPhase('complete');
      else setPhase('stable');
    }, 1200);
  }, [phase]);

  // after 2 manual recalls, auto-recall takes over until drift hits 100%
  useEffect(() => {
    if (phase === 'complete') { setAutoMode(false); return; }
    if (autoMode && phase === 'stable') {
      const id = setTimeout(() => recall(), 900);
      return () => clearTimeout(id);
    }
    // turn on auto mode once we've reached 2 manual recalls
    if (recallCount >= 2 && drift < 1 && !autoMode && phase === 'stable') {
      setAutoMode(true);
    }
  }, [phase, recallCount, autoMode, drift]);

  const reset = () => {
    setNodes(ANCHOR_NODES.map(([x,y]) => ({ x, y, ax: x, ay: y })));
    setDrift(0);
    setRecallCount(0);
    setPhase('stable');
    setParticles([]);
    setAutoMode(false);
  };

  const phaseLabel = {
    stable: autoMode ? 'auto recall · pending' : (recallCount === 0 ? 'consolidated' : 'temporarily stable'),
    dismantling: 'recall — dismantling',
    labile: 'labile window',
    rebuilding: 'reconstructing',
    complete: 'unrecognizable',
  }[phase];
  const phaseTitle = {
    stable: recallCount === 0 ? 'A memory.' : 'Another memory.',
    dismantling: 'Proteins degrade.',
    labile: 'No memory exists.',
    rebuilding: 'A new memory.',
    complete: 'A different memory.',
  }[phase];
  const phaseDesc = {
    stable: recallCount === 0
      ? 'The synaptic scaffolding holds a pattern. We call it a fixed past. Click recall to reactivate it.'
      : (autoMode
          ? 'The mind, once it has remembered, cannot stop. Each recall reconstructs again.'
          : 'A new pattern, presented to consciousness as the same memory. Click recall to reactivate again.'),
    dismantling: 'The molecular scaffold that holds the pattern is physically dismantled. Old proteins are degraded.',
    labile: 'For approximately six hours, the synaptic pattern temporarily ceases to exist in its stable form.',
    rebuilding: 'The brain synthesizes new proteins. The pattern is assembled from present-moment conditions.',
    complete: 'The memory you began with is gone. What remains is a series of present-moment reconstructions, each one calling itself the past.',
  }[phase];

  // qualitative drift label — no spurious precision
  const driftLabel =
    drift <= 0.001 ? 'original' :
    drift < 0.25   ? 'lightly altered' :
    drift < 0.50   ? 'drifting' :
    drift < 0.75   ? 'reshaped' :
    drift < 1.00   ? 'transforming' :
                     'unrecognizable';

  const nodeOpacity = phase === 'labile' ? 0.18 : (phase === 'dismantling' ? 0.45 : 1);
  const edgeOpacity = phase === 'labile' ? 0.08 : (phase === 'dismantling' ? 0.30 : 0.85);

  return (
    <div style={reconStyles.wrap}>
      <div style={reconStyles.canvas}>
        <svg viewBox="0 0 400 300" style={{ position: 'absolute', inset: 0, width: '100%', height: '100%' }}>
          <defs>
            <radialGradient id="recon-glow">
              <stop offset="0%" stopColor="rgba(207,191,149,0.45)" />
              <stop offset="60%" stopColor="rgba(207,191,149,0.10)" />
              <stop offset="100%" stopColor="rgba(207,191,149,0)" />
            </radialGradient>
            <filter id="recon-soft">
              <feGaussianBlur stdDeviation="0.5" />
            </filter>
          </defs>

          {/* center halo */}
          <circle cx="200" cy="150" r="120" fill="url(#recon-glow)" opacity={phase === 'stable' ? 0.9 : 0.4} style={{ transition: 'opacity 800ms cubic-bezier(0.4,0,0.2,1)' }} />

          {/* edges */}
          <g style={{ opacity: edgeOpacity, transition: 'opacity 800ms cubic-bezier(0.4,0,0.2,1)' }}>
            {NODE_EDGES.map(([a, b], i) => {
              const na = nodes[a]; const nb = nodes[b];
              return (
                <line key={i}
                  x1={na.x * 400} y1={na.y * 300}
                  x2={nb.x * 400} y2={nb.y * 300}
                  stroke="var(--glow)" strokeWidth="0.6" opacity="0.5"
                  style={{ transition: 'all 1200ms cubic-bezier(0.4,0,0.2,1)' }} />
              );
            })}
          </g>

          {/* nodes */}
          <g style={{ opacity: nodeOpacity, transition: 'opacity 800ms cubic-bezier(0.4,0,0.2,1)' }}>
            {nodes.map((n, i) => (
              <g key={i} style={{ transition: 'all 1200ms cubic-bezier(0.4,0,0.2,1)' }}>
                <circle cx={n.x * 400} cy={n.y * 300} r="3.5" fill="var(--glow)" opacity="0.9" />
                <circle cx={n.x * 400} cy={n.y * 300} r="6" fill="var(--glow)" opacity="0.18" />
              </g>
            ))}
          </g>

          {/* particles (proteins) during labile */}
          <g>
            {particles.map(p => (
              <circle key={p.id} cx={p.x * 400} cy={p.y * 300} r="1.2"
                fill="var(--glow)" opacity={Math.max(0, p.life) * 0.7} />
            ))}
          </g>

          {/* progress arc during labile */}
          {phase === 'labile' && (
            <g>
              <circle cx="200" cy="150" r="100" fill="none"
                stroke="rgba(207,191,149,0.12)" strokeWidth="1" />
              <circle cx="200" cy="150" r="100" fill="none"
                stroke="var(--glow)" strokeWidth="1"
                strokeDasharray={`${2 * Math.PI * 100 * labileT} ${2 * Math.PI * 100}`}
                transform="rotate(-90 200 150)" />
            </g>
          )}
        </svg>

        {/* corner labels */}
        <div style={{
          position: 'absolute', top: 14, left: 16,
          fontFamily: 'var(--font-ui)', fontSize: 9, letterSpacing: '0.32em',
          textTransform: 'uppercase', color: 'var(--muted)',
        }}>amygdala · fear circuit</div>
        <div style={{
          position: 'absolute', bottom: 14, left: 16,
          fontFamily: 'var(--font-ui)', fontSize: 9, letterSpacing: '0.32em',
          textTransform: 'uppercase', color: 'var(--glow)',
          transition: 'color 800ms cubic-bezier(0.4,0,0.2,1)',
        }}>
          state · {phaseLabel}
        </div>
      </div>

      <div style={reconStyles.panel}>
        <div style={reconStyles.state}>state {String(recallCount).padStart(2, '0')}</div>
        <h4 style={reconStyles.stateText}>{phaseTitle}</h4>
        <p style={reconStyles.desc}>{phaseDesc}</p>

        <div style={reconStyles.drift}>
          <div style={{ display: 'flex', justifyContent: 'space-between' }}>
            <span>The memory now</span>
            <span style={{ color: 'var(--glow)', fontStyle: 'italic' }}>{driftLabel}</span>
          </div>
          <div style={reconStyles.driftBar}>
            <div style={{ ...reconStyles.driftFill, width: `${drift * 100}%` }}></div>
          </div>
        </div>

        {phase === 'labile' && (
          <div style={reconStyles.drift}>
            <div style={{ display: 'flex', justifyContent: 'space-between' }}>
              <span>~6 hour window</span>
              <span style={{ color: 'var(--glow)' }}>labile</span>
            </div>
            <div style={reconStyles.windowBar}>
              <div style={{ ...reconStyles.windowFill, width: `${labileT * 100}%` }}></div>
            </div>
          </div>
        )}

        <div style={{ display: 'flex', gap: 10, marginTop: 'auto' }}>
          {phase === 'complete' ? (
            <button className="luma-button luma-button--primary" onClick={reset} style={{ flex: 1 }}>
              reset
            </button>
          ) : autoMode ? (
            <button className="luma-button" onClick={reset} style={{ flex: 1 }}>
              stop · reset
            </button>
          ) : (
            <>
              <button className="luma-button luma-button--primary"
                disabled={phase !== 'stable'}
                onClick={recall}
                style={{ flex: 1, opacity: phase === 'stable' ? 1 : 0.5, cursor: phase === 'stable' ? 'pointer' : 'wait' }}>
                recall
              </button>
              {recallCount > 0 && (
                <button className="luma-button" onClick={reset} style={{ flex: 'none' }}>reset</button>
              )}
            </>
          )}
        </div>

        <div style={reconStyles.meta}>
          <span>{autoMode || phase === 'complete' ? 'reconstructions' : 'recalls'}</span>
          <span style={reconStyles.metaVal}>{recallCount}</span>
        </div>
      </div>
    </div>
  );
}

window.Reconsolidation = Reconsolidation;
