/* global React */
/*
  Needs mode — Spirit diagnostic on the left, stacked Need cards on the right.
  Reads PORT_SLOTS / PORT_ELEM / pad from window.
*/

const { useState: useNeedState, useEffect: useNeedEffect } = React;

function NeedsMode({ state, dispatch, resolving }) {
  const needs = deriveNeeds(state);
  const [cooldown, setCooldown] = useNeedState(false);

  function trigger(act) {
    if (cooldown || resolving) return;
    if (act.kind === 'mode') { dispatch({ type: 'SET_MODE', mode: act.target }); return; }
    if (act.kind === 'noop')  return;
    if (act.kind !== 'feed') {
      setCooldown(true); setTimeout(() => setCooldown(false), 360);
    }
    if (act.kind === 'feed') {
      dispatch({ type: 'CARE_ACTION', kind: 'feed', food: act.food });
    } else {
      dispatch({ type: 'CARE_ACTION', kind: act.kind });
    }
  }

  return (
    <div style={{ display: 'grid', gridTemplateColumns: '340px 1fr', gap: 14, height: '100%' }}>
      {/* LEFT — Diagnostic */}
      <div className="panel brackets" style={{ display: 'flex', flexDirection: 'column' }}>
        <div className="row" style={{ padding: '8px 14px', borderBottom: '1px solid var(--ink-faded)' }}>
          <span className="label label-ink">Spirit · Diagnostic</span>
        </div>
        <div style={{ height: 260, position: 'relative', overflow: 'hidden' }}>
          <NascentMote ascending={state.ascending} state={state} />
        </div>
        <div style={{ padding: '14px', borderTop: '1px solid var(--ink-faded)' }}>
          <div className="row" style={{ justifyContent: 'space-between', alignItems: 'baseline', marginBottom: 10 }}>
            <span className="label label-ink">Care Meters</span>
          </div>
          <div className="col gap-6">
            <DiagBar label="Bond"      value={state.care.bondPct}   tone="gold"  hint={state.care.bond} />
            <DiagBar label="Will"      value={state.care.will}      tone="ink"   hint={willHint(state.care.will)} />
            <DiagBar label="Fullness"  value={state.care.fullness}  tone="amber"
                     hint={state.care.fullness > 90 ? 'Full' : state.care.fullness < 30 ? 'Hungry' : ''}
                     alert={state.care.fullness < 30} />
            <DiagBar label="Fatigue"   value={state.care.fatigue}   tone="crit"
                     hint={state.care.fatigue > 80 ? 'Forced' : state.care.fatigue > 55 ? 'Pushing' : ''}
                     alert={state.care.fatigue > 55} />
            <DiagBar label="Weight"    value={state.care.weight}    tone="ink"
                     hint={state.care.weight <= 9 ? 'Wasting' : state.care.weight < 14 ? 'Frail' : ''}
                     alert={state.care.weight < 14} />
          </div>
        </div>
      </div>

      {/* RIGHT — needs stack */}
      <div className="col gap-10" style={{ minHeight: 0 }}>
        <div className="row" style={{ justifyContent: 'space-between', alignItems: 'baseline', padding: '0 2px' }}>
          <span className="label label-ink">The Spirit Needs</span>
          <span className="mono" style={{ fontSize: 10, color: 'var(--sepia)' }}>
            {needs.length} OUTSTANDING · {needs.filter(n => n.tier === 'urgent').length} URGENT
          </span>
        </div>

        {needs.length === 0 && (
          <div className="panel" style={{ padding: 22, textAlign: 'center' }}>
            <div className="fell" style={{ fontSize: 18, color: 'var(--ok)' }}>SETTLED</div>
            <div className="mono" style={{ fontSize: 11, color: 'var(--sepia)', marginTop: 6 }}>
              The spirit asks nothing. Tend to training or push the day along.
            </div>
            <button className="btn" style={{ marginTop: 12, padding: '8px 16px' }}
              onClick={() => dispatch({ type: 'SET_MODE', mode: 'train' })}>
              Open Training ▸
            </button>
          </div>
        )}

        {needs.map(n => (
          n.id === 'hungry'
            ? <FeedNeedCard key={n.id} need={n} state={state} onAct={trigger} disabled={resolving} />
            : <BigNeedCard  key={n.id} need={n} onAct={trigger} disabled={cooldown || resolving} />
        ))}
      </div>
    </div>
  );
}

// ====================================================================
// Need derivation — order: urgent → soft → beckon
// ====================================================================
function deriveNeeds(state) {
  const c = state.care;
  const out = [];

  if (c.fatigue > 55) {
    const atSleep = (state.slotIdx % 4) === (state.sleepSlot ?? 0);
    out.push({
      id: 'tired', tier: 'urgent', tag: 'Tired',
      meter: 'Fatigue', value: c.fatigue, color: 'var(--crit)',
      line: atSleep
        ? 'Wings drag — and it is the sleep hour. Rest now for a full night; act and pay dearly.'
        : 'Wings drag. A nap eases it, but a true rest only lands at the sleep hour (Night).',
      actions: [
        { name: 'Rest', sub: atSleep ? 'full clear · sleep hour · slot 1' : 'nap · −60 fatigue · slot 1', kind: 'rest', primary: true },
      ],
    });
  }

  if (c.fullness < 40) out.push({
    id: 'hungry', tier: c.fullness < 25 ? 'urgent' : 'soft', tag: 'Hungry',
    meter: 'Fullness', value: c.fullness, color: 'var(--stamp-amber)',
    line: 'The aether-belly is light. Pick a food — staple sustains, offerings add +3 Mastery to a vein.',
    // No actions[] — FeedNeedCard renders its own food picker from inventory.
  });

  return out;
}

function cap(s) { return s[0].toUpperCase() + s.slice(1).toLowerCase(); }
function willHint(v) { return v < 30 ? 'Wild' : v > 70 ? 'Bridled' : 'Settled'; }

// ====================================================================
// DiagBar
// ====================================================================
function DiagBar({ label, value, hint, tone, alert, max = 100 }) {
  const toneVar = { gold:'var(--gold)', ink:'var(--ink)', ok:'var(--ok)', amber:'var(--stamp-amber)', crit:'var(--crit)' }[tone] || 'var(--ink)';
  const pct = Math.max(0, Math.min(100, (value / max) * 100));
  return (
    <div className="row gap-6" style={{ alignItems: 'center' }}>
      <span style={{ width: 7, height: 7, borderRadius: 7, background: alert ? toneVar : 'transparent', border: alert ? 'none' : '1px solid transparent' }} />
      <div className="label label-ink" style={{ width: 64, fontSize: 9 }}>{label}</div>
      <div style={{ flex: 1, height: 10, border: '1px solid var(--ink-faded)', background: 'rgba(255,255,255,0.2)', position: 'relative' }}>
        <div style={{ position: 'absolute', inset: 0, width: `${pct}%`, background: toneVar, opacity: 0.85, transition: 'width 200ms ease' }} />
      </div>
      <div className="mono" style={{ width: 32, textAlign: 'right', fontSize: 11, fontWeight: 600 }}>
        <window.Num value={value} pad={2} />{max !== 100 ? <span style={{ fontSize: 8, color: 'var(--ink-faded)' }}>/{max}</span> : ''}
      </div>
      <div className="elite" style={{ width: 54, fontSize: 9, color: alert ? toneVar : 'var(--sepia)' }}>{hint || ''}</div>
    </div>
  );
}

// ====================================================================
// BigNeedCard
// ====================================================================
function BigNeedCard({ need, onAct, disabled }) {
  const tierBadge = {
    urgent: { label: 'URGENT', color: 'var(--crit)'        },
    soft:   { label: 'SOFT',   color: 'var(--gold)'        },
    beckon: { label: 'BECKON', color: 'var(--stamp-amber)' },
  }[need.tier];
  const bgTint = colorTint(need.color);

  return (
    <div className="panel" style={{
      padding: '12px 14px',
      borderLeft: `5px solid ${need.color}`,
      background: bgTint,
    }}>
      <div className="row gap-10" style={{ alignItems: 'baseline', marginBottom: 6 }}>
        <span className="fell" style={{ fontSize: 19, color: need.color, letterSpacing: '0.04em' }}>
          {need.tag.toUpperCase()}
        </span>
        <span className="elite" style={{
          fontSize: 9.5, padding: '1px 6px',
          border: `1px solid ${tierBadge.color}`, color: tierBadge.color,
          letterSpacing: '0.18em',
        }}>{tierBadge.label}</span>
        <span style={{ flex: 1 }} />
        <span className="mono" style={{ fontSize: 11, color: 'var(--sepia)' }}>
          {need.meter} · <span style={{ color: 'var(--ink)', fontWeight: 700 }}><window.Num value={need.value} /></span>
        </span>
      </div>
      <div style={{ fontSize: 12, color: 'var(--sepia)', fontFamily: 'Special Elite, monospace', lineHeight: 1.45, marginBottom: 10 }}>
        {need.line}
      </div>
      <div className="row gap-6">
        {need.actions.map((a, i) => {
          const off = disabled || a.disabled;
          return (
            <button key={i} disabled={off}
              onClick={() => !off && onAct(a)}
              style={{
                flex: 1, padding: '9px 12px',
                cursor: off ? 'not-allowed' : 'pointer',
                border: `1.5px solid ${a.primary ? need.color : 'var(--ink)'}`,
                background: a.primary ? colorTint(need.color, 0.16) : 'rgba(244, 236, 214, 0.6)',
                color: a.primary ? need.color : 'var(--ink)',
                fontFamily: 'IM Fell English SC, serif',
                fontSize: 13, letterSpacing: '0.04em',
                opacity: off ? 0.45 : 1,
                textAlign: 'left',
                transition: 'background 120ms ease',
              }}>
              <div>{a.name}</div>
              <div className="mono" style={{ fontSize: 9, color: 'var(--sepia)', marginTop: 2, letterSpacing: '0.08em' }}>{a.sub}</div>
            </button>
          );
        })}
      </div>
    </div>
  );
}

// ====================================================================
// FeedNeedCard — the food picker. Surfaces the top 3 foods inline; a "+"
// reveals the rest. Foods come from the inventory (staple bank + each
// elemental offering bank with count ≥ 1). Ranked so the spirit's
// current-slot element offering surfaces first, then heaviest banks,
// then staple as the everyday fallback.
// ====================================================================
function FeedNeedCard({ need, state, onAct, disabled }) {
  const PORT_SLOTS = window.PORT_SLOTS;
  const PORT_ELEM  = window.PORT_ELEM;
  const slot = PORT_SLOTS[state.slotIdx];
  const slotMain = slot.pair[0];

  // Build the foods list (count > 0 only)
  const offerings = state.resources.offerings;
  const foods = [];

  // Each elemental offering with stock
  Object.entries(offerings).forEach(([k, n]) => {
    if (n > 0 && state.elements[k]?.unlocked) {
      foods.push({
        id: `offering:${k}`, kind: 'offering', element: k,
        name: `${PORT_ELEM[k].name} Offering`,
        glyph: PORT_ELEM[k].glyph, icon: PORT_ELEM[k].icon, color: PORT_ELEM[k].color,
        stock: n,
        fullness: 28, gain: `+3 ${PORT_ELEM[k].name}`,
        priority: (k === slotMain ? 100 : 50) + n,        // slot main beats bigger banks
      });
    }
  });
  // Staple — always last in priority, but always present if stocked
  if (state.resources.staple > 0) {
    foods.push({
      id: 'staple', kind: 'staple', name: 'Staple', glyph: '◦', color: 'var(--ink)',
      stock: state.resources.staple, fullness: 22, gain: 'sustains',
      priority: 10,
    });
  }
  foods.sort((a, b) => b.priority - a.priority);
  const top3   = foods.slice(0, 3);
  const others = foods.slice(3);
  const [open, setOpen] = useNeedState(false);

  const bgTint = colorTint(need.color);
  const tierBadge = {
    urgent: { label: 'URGENT', color: 'var(--crit)'        },
    soft:   { label: 'SOFT',   color: 'var(--gold)'        },
    beckon: { label: 'BECKON', color: 'var(--stamp-amber)' },
  }[need.tier];
  const full = state.care.fullness >= 90;

  return (
    <div className="panel" style={{
      padding: '12px 14px',
      borderLeft: `5px solid ${need.color}`,
      background: bgTint,
    }}>
      <div className="row gap-10" style={{ alignItems: 'baseline', marginBottom: 6 }}>
        <span className="fell" style={{ fontSize: 19, color: need.color, letterSpacing: '0.04em' }}>FEED</span>
        <span className="elite" style={{
          fontSize: 9.5, padding: '1px 6px',
          border: `1px solid ${tierBadge.color}`, color: tierBadge.color,
          letterSpacing: '0.18em',
        }}>{tierBadge.label}</span>
        <span style={{ flex: 1 }} />
        <span className="mono" style={{ fontSize: 11, color: 'var(--sepia)' }}>
          Fullness · <span style={{ color: 'var(--ink)', fontWeight: 700 }}><window.Num value={state.care.fullness} /></span>
        </span>
      </div>
      <div style={{ fontSize: 12, color: 'var(--sepia)', fontFamily: 'Special Elite, monospace',
        lineHeight: 1.45, marginBottom: 10 }}>
        {need.line}
      </div>

      {foods.length === 0 ? (
        <div className="row gap-6" style={{ alignItems: 'center' }}>
          <span className="mono" style={{ fontSize: 11, color: 'var(--crit)', flex: 1 }}>
            ◇ Inventory empty — forage or expedition to restock.
          </span>
          <button onClick={() => onAct({ kind: 'forage' })} disabled={disabled || full}
            style={{ ...feedBtnStyle(disabled || full, 'var(--sepia)'),
                     background: 'rgba(244, 236, 214, 0.6)', color: 'var(--ink)' }}>
            <div className="fell" style={{ fontSize: 13, letterSpacing: '0.04em' }}>Forage ▸</div>
            <div className="mono" style={{ fontSize: 9, color: 'var(--sepia)', marginTop: 1 }}>
              slot · +4 staple
            </div>
          </button>
        </div>
      ) : (
        <>
          <div className="row gap-6" style={{ alignItems: 'stretch', flexWrap: 'wrap' }}>
            {top3.map(food => (
              <FoodChip key={food.id} food={food} slotMain={slotMain}
                        disabled={disabled || full}
                        onClick={() => onAct({ kind: 'feed', food: food.element || 'staple' })} />
            ))}
            {others.length > 0 && (
              <button onClick={() => setOpen(o => !o)}
                style={{
                  width: 44, border: '1.5px dashed var(--ink-faded)',
                  background: open ? 'rgba(26, 46, 74, 0.06)' : 'transparent',
                  cursor: 'pointer', fontFamily: 'IM Fell English SC, serif',
                  fontSize: 22, color: 'var(--ink-soft)', lineHeight: 1,
                }}
                title={open ? 'Hide other foods' : `Show ${others.length} more`}>
                {open ? '×' : '+'}
              </button>
            )}
          </div>
          {open && others.length > 0 && (
            <div className="row gap-6" style={{
              marginTop: 8, paddingTop: 8, borderTop: '1px dashed var(--ink-faded)',
              alignItems: 'stretch', flexWrap: 'wrap',
            }}>
              {others.map(food => (
                <FoodChip key={food.id} food={food} slotMain={slotMain}
                          disabled={disabled || full}
                          onClick={() => onAct({ kind: 'feed', food: food.element || 'staple' })} />
              ))}
            </div>
          )}
          {full && (
            <div className="mono" style={{ fontSize: 10, color: 'var(--sepia)', marginTop: 8, letterSpacing: '0.10em' }}>
              ◌ FULLNESS &gt; 90 — the spirit cannot take another bite.
            </div>
          )}
        </>
      )}
    </div>
  );
}

function feedBtnStyle(off, color) {
  return {
    flex: '1 1 0', minWidth: 120, padding: '9px 11px',
    cursor: off ? 'not-allowed' : 'pointer',
    border: `1.5px solid ${color}`,
    background: 'rgba(244, 236, 214, 0.6)',
    color, fontFamily: 'IM Fell English SC, serif',
    fontSize: 13, letterSpacing: '0.04em',
    opacity: off ? 0.45 : 1, textAlign: 'left',
    transition: 'background 120ms ease',
  };
}

function FoodChip({ food, slotMain, disabled, onClick }) {
  const isSlotPick = food.kind === 'offering' && food.element === slotMain;
  return (
    <button onClick={onClick} disabled={disabled}
      style={{
        flex: '1 1 0', minWidth: 130, padding: '8px 10px',
        cursor: disabled ? 'not-allowed' : 'pointer',
        border: `1.5px solid ${food.color}`,
        background: isSlotPick ? `${food.color}1f` : 'rgba(244, 236, 214, 0.6)',
        color: 'var(--ink)', textAlign: 'left',
        opacity: disabled ? 0.45 : 1,
        position: 'relative',
        transition: 'background 120ms ease, transform 80ms ease',
      }}>
      <div className="row gap-6" style={{ alignItems: 'baseline' }}>
        <span style={{ color: food.color, fontFamily: 'IM Fell English SC, serif', fontSize: 16, lineHeight: 1 }}>
          {food.icon ? <img src={food.icon} alt="" style={{ width: 16, height: 16, objectFit: 'contain', display: 'block' }} /> : food.glyph}
        </span>
        <span className="fell" style={{ fontSize: 14, lineHeight: 1, color: food.color }}>{food.name}</span>
        <span style={{ flex: 1 }} />
        <span className="mono" style={{ fontSize: 10, color: 'var(--ink-soft)', fontWeight: 600 }}>×{food.stock}</span>
      </div>
      <div className="mono" style={{ fontSize: 9.5, color: 'var(--sepia)', marginTop: 4, letterSpacing: '0.08em' }}>
        +{food.fullness} fullness · {food.gain}
      </div>
      {isSlotPick && (
        <div style={{
          position: 'absolute', top: -1, right: -1, padding: '1px 6px',
          background: food.color, color: 'var(--paper-light)',
          fontFamily: 'IM Fell English SC, serif', fontSize: 9, letterSpacing: '0.12em',
        }}>
          SLOT
        </div>
      )}
    </button>
  );
}

function colorTint(c, alpha = 0.06) {
  // Map known CSS-var palette entries to a paper-tinted background.
  const map = {
    'var(--crit)':        `rgba(161, 43, 34, ${alpha})`,
    'var(--stamp-red)':   `rgba(161, 43, 34, ${alpha})`,
    'var(--stamp-amber)': `rgba(184, 99, 42, ${alpha})`,
    'var(--gold)':        `rgba(176, 140, 60, ${alpha})`,
    'var(--el-fire)':     `rgba(184, 99, 42, ${alpha})`,
    'var(--el-air)':      `rgba(42, 111, 138, ${alpha})`,
    'var(--el-water)':    `rgba(53, 94, 125, ${alpha})`,
    'var(--el-earth)':    `rgba(122, 82, 48, ${alpha})`,
  };
  return map[c] || `rgba(244, 236, 214, ${alpha + 0.4})`;
}

// ====================================================================
// NascentMote — the spirit's portrait in the diagnostic pane. Uses the
// uploaded illustration matrix: drift mote at R0, the non-harnessed
// Lesser form at R1+ keyed by the strongest vein.
// ====================================================================
function NascentMote({ ascending, state }) {
  const src = window.spiritIconSrc(state);
  const isMote = !state || state.rank === 0;
  const formLabel = isMote ? 'NASCENT MOTE · CRADLE STUDY' : `${(state.formName || '').toUpperCase()} · FIELD STUDY`;
  return (
    <div style={{ position: 'relative', width: '100%', height: '100%' }} className={ascending ? 'shake' : ''}>
      {/* paper-frame annotation */}
      <div className="mono" style={{
        position: 'absolute', top: 10, left: 14, right: 14, zIndex: 2,
        fontSize: 9.5, color: 'var(--sepia)', letterSpacing: '0.14em',
        display: 'flex', justifyContent: 'space-between', pointerEvents: 'none',
      }}>
        <span>FIG. 0 — {formLabel}</span>
        <span style={{ opacity: 0.7 }}>{isMote ? '◦ R0' : '◇ R1'}</span>
      </div>
      {/* faint cradle rule */}
      <svg viewBox="0 0 600 360" preserveAspectRatio="xMidYMid meet"
           style={{ position: 'absolute', inset: 0, width: '100%', height: '100%' }}>
        <line x1="40" y1="300" x2="560" y2="300" stroke="var(--ink)" strokeOpacity="0.25" strokeDasharray="3 5" />
        <line x1="40" y1="305" x2="560" y2="305" stroke="var(--ink)" strokeOpacity="0.10" />
      </svg>
      {/* the spirit itself — the SVG filter keys the asset's white background
          to alpha so only the painted illustration sits on the paper. */}
      <img src={src} alt=""
           style={{
             position: 'absolute', inset: 0, margin: 'auto',
             width: '78%', height: '88%', objectFit: 'contain',
             filter: 'url(#sh-dropwhite) drop-shadow(0 4px 6px rgba(74, 54, 38, 0.18))',
           }} />
    </div>
  );
}

Object.assign(window, { NeedsMode });
