// ============================================================
// UI — Header, Side Panel, Bottom Timeline Scrubber
// ============================================================
/* global React */

const MONTHS_FULL = [
  'January', 'February', 'March', 'April', 'May', 'June',
  'July', 'August', 'September', 'October', 'November', 'December',
];
const MONTHS_SHORT = ['Jan','Feb','Mar','Apr','May','Jun','Jul','Aug','Sep','Oct','Nov','Dec'];

const MW = {
  1:[1,4], 2:[5,8], 3:[9,13], 4:[14,17], 5:[18,21], 6:[22,26],
  7:[27,30], 8:[31,34], 9:[35,39], 10:[40,43], 11:[44,47], 12:[48,52],
};

function weekToMonth(w) {
  for (let m = 1; m <= 12; m++) {
    const [a, b] = MW[m];
    if (w >= a && w <= b) return { month: m, weekInMonth: w - a + 1, totalInMonth: b - a + 1 };
  }
  return { month: 1, weekInMonth: 1, totalInMonth: 4 };
}

function Header({ week, weekCount }) {
  const { month, weekInMonth, totalInMonth } = weekToMonth(week);
  return (
    <header style={{
      padding: '26px 56px 14px',
      display: 'flex',
      alignItems: 'flex-end',
      justifyContent: 'space-between',
      gap: 48,
      position: 'relative',
      flexShrink: 0,
      animation: 'fadeUp 0.7s ease both',
    }}>
      <div>
        <div className="eyebrow" style={{ marginBottom: 10 }}>
          The Festival Atlas of India
        </div>
        <h1 className="t-display" style={{
          fontSize: 'clamp(40px, 5vw, 82px)',
          lineHeight: 0.95,
          fontWeight: 400,
          letterSpacing: '-0.01em',
        }}>
          Land of <span style={{ fontStyle: 'italic', color: 'var(--saffron)' }}>Festival</span>
          <span className="t-hindi" style={{
            fontSize: '0.28em',
            color: 'var(--paper-mute)',
            marginLeft: 18,
            letterSpacing: '0.02em',
            verticalAlign: 'middle',
          }}>
            उत्सवों की भूमि
          </span>
        </h1>
        <p className="t-serif" style={{
          marginTop: 10,
          fontSize: 17,
          maxWidth: 640,
          fontStyle: 'italic',
          color: 'var(--paper-mute)',
          fontWeight: 400,
          lineHeight: 1.4,
        }}>
          A year in India is never quiet. Drag the pointer across the months and watch the country remember what it has always been — a constellation of harvests, monsoons, full moons and small village fairs.
        </p>
      </div>

      <div style={{
        textAlign: 'right',
        animation: 'fadeUp 0.9s ease both',
        display: 'flex',
        flexDirection: 'column',
        alignItems: 'flex-end',
        gap: 2,
        width: 320,
        flexShrink: 0,
      }}>
        <div className="eyebrow" style={{ marginBottom: 6 }}>You are viewing</div>

        <div className="t-display" style={{
          fontSize: 42,
          color: 'var(--paper)',
          lineHeight: 1.0,
          marginBottom: 2,
        }}>
          {MONTHS_FULL[month - 1]}
        </div>

        <div className="t-serif" style={{
          fontSize: 14,
          fontStyle: 'italic',
          color: 'var(--paper-mute)',
        }}>
          Week {weekInMonth} of {totalInMonth}
          <span className="t-mono" style={{
            marginLeft: 8,
            fontSize: 10,
            color: 'oklch(0.48 0.02 60)',
            letterSpacing: '0.18em',
            fontFamily: 'JetBrains Mono, ui-monospace, monospace',
            fontStyle: 'normal',
          }}>W{String(week).padStart(2, '0')}/52</span>
        </div>

        <div style={{
          marginTop: 16,
          paddingTop: 12,
          borderTop: '1px solid oklch(0.30 0.020 55)',
          display: 'flex',
          alignItems: 'baseline',
          gap: 10,
          width: '100%',
          justifyContent: 'flex-end',
        }}>
          <div className="t-display" style={{
            fontSize: 56,
            color: 'var(--saffron)',
            lineHeight: 1.0,
            fontVariantNumeric: 'tabular-nums',
          }}>
            {String(weekCount).padStart(2, '0')}
          </div>
          <div className="t-serif" style={{
            fontSize: 15,
            fontStyle: 'italic',
            color: 'var(--paper-mute)',
            textAlign: 'left',
            lineHeight: 1.25,
            maxWidth: 130,
          }}>
            {weekCount === 1 ? 'festival lit' : 'festivals lit'} <br/> at once
          </div>
        </div>
      </div>
    </header>
  );
}

function SidePanel({
  weekFestivals,
  hoveredPin, selectedPin, setSelectedPin,
  didYouKnow,
}) {
  const focusFest = useFocusFestival(weekFestivals, hoveredPin, selectedPin);

  const stateGroups = React.useMemo(() => {
    const groups = new Map();
    weekFestivals.forEach((f) => {
      const key = f.pan ? 'Across India' : (f.states.join(', ') || 'India');
      if (!groups.has(key)) groups.set(key, []);
      groups.get(key).push(f);
    });
    return [...groups.entries()];
  }, [weekFestivals]);

  return (
    <aside style={{
      width: 420,
      minWidth: 420,
      maxWidth: 420,
      padding: '4px 40px 4px 0',
      display: 'flex',
      flexDirection: 'column',
      gap: 18,
      height: '100%',
      minHeight: 0,
      overflow: 'hidden',
    }}>

      <FocusCard fest={focusFest} onClose={() => setSelectedPin(null)} hasSelection={!!selectedPin} />

      <div style={{
        flex: 1,
        minHeight: 0,
        overflow: 'auto',
        paddingRight: 8,
      }}>
        <div className="eyebrow" style={{ marginBottom: 12, position: 'sticky', top: 0, background: 'var(--ink)', paddingBottom: 8, zIndex: 1 }}>This week, across the country</div>
        {weekFestivals.length === 0 ? (
          <div className="t-serif" style={{
            fontStyle: 'italic',
            color: 'var(--paper-mute)',
            fontSize: 16,
            padding: '20px 0',
            lineHeight: 1.5,
          }}>
            A quieter week. Move the pointer to find a celebration.
          </div>
        ) : (
          <div style={{ display: 'flex', flexDirection: 'column', gap: 14 }}>
            {stateGroups.map(([state, items]) => (
              <StateRow key={state} state={state} items={items} setSelectedPin={setSelectedPin} />
            ))}
          </div>
        )}
      </div>

      <DidYouKnow fact={didYouKnow} />
    </aside>
  );
}

function useFocusFestival(weekFestivals, hoveredPin, selectedPin) {
  return React.useMemo(() => {
    const lookup = (id) => weekFestivals.find((f) => f.id === id);
    return lookup(hoveredPin) || lookup(selectedPin) || null;
  }, [weekFestivals, hoveredPin, selectedPin]);
}

function FocusCard({ fest, onClose, hasSelection }) {
  if (!fest) return (
    <div style={{
      padding: '14px 18px',
      border: '1px dashed oklch(0.30 0.020 55)',
      borderRadius: 4,
      color: 'var(--paper-mute)',
      fontSize: 14,
      flexShrink: 0,
    }} className="t-serif">
      <span style={{ fontStyle: 'italic' }}>Hover or click a glowing pin to learn its story.</span>
    </div>
  );

  return (
    <div style={{
      padding: '18px 22px',
      background: 'oklch(0.20 0.018 55 / 0.85)',
      border: '1px solid oklch(0.62 0.165 28 / 0.45)',
      borderRadius: 4,
      animation: 'fadeUp 0.35s ease both',
      position: 'relative',
      flexShrink: 0,
    }}>
      <div style={{ display: 'flex', gap: 14, alignItems: 'flex-start' }}>
        <div style={{ flexShrink: 0, paddingTop: 2 }}>
          <window.LOF_Icons.FestivalIcon festival={fest} size={52} />
        </div>
        <div style={{ flex: 1, minWidth: 0 }}>
          <div className="eyebrow" style={{
            color: 'var(--saffron)',
            marginBottom: 6,
            fontSize: 10,
          }}>{fest.level} · {fest.type}</div>

          <h3 className="t-display" style={{
            fontSize: 24,
            lineHeight: 1.1,
            marginBottom: 4,
            color: 'var(--paper)',
            fontWeight: 400,
            paddingRight: hasSelection ? 24 : 0,
          }}>{fest.name}</h3>

          <div className="t-serif" style={{
            fontStyle: 'italic',
            color: 'var(--gold)',
            fontSize: 14,
            marginBottom: 10,
          }}>
            {fest.pan ? 'Across India' : fest.states.join(' · ')} · {fest.timeLabel}
          </div>

          <p className="t-serif" style={{
            fontSize: 15,
            lineHeight: 1.5,
            color: 'oklch(0.86 0.015 75)',
          }}>{fest.description}</p>
        </div>
      </div>

      {hasSelection && (
        <button
          onClick={onClose}
          style={{
            position: 'absolute',
            top: 14, right: 14,
            background: 'transparent',
            border: '1px solid oklch(0.40 0.02 55)',
            color: 'var(--paper-mute)',
            width: 22, height: 22,
            borderRadius: '50%',
            cursor: 'pointer',
            fontSize: 12,
            lineHeight: 1,
          }}
          aria-label="Close"
        >×</button>
      )}
    </div>
  );
}

function StateRow({ state, items, setSelectedPin }) {
  return (
    <div style={{
      paddingBottom: 12,
      borderBottom: '1px solid oklch(0.25 0.018 55)',
    }}>
      <div className="t-sans" style={{
        fontSize: 11,
        textTransform: 'uppercase',
        letterSpacing: '0.18em',
        color: 'var(--paper-mute)',
        marginBottom: 8,
        fontWeight: 500,
      }}>{state}</div>
      <div style={{ display: 'flex', flexDirection: 'column', gap: 4 }}>
        {items.map((f) => (
          <button
            key={f.id}
            onClick={() => setSelectedPin(f.id)}
            style={{
              textAlign: 'left',
              background: 'transparent',
              border: 'none',
              padding: '4px 0',
              cursor: 'pointer',
              display: 'flex',
              alignItems: 'center',
              gap: 10,
            }}
            onMouseEnter={(e) => e.currentTarget.style.background = 'oklch(0.22 0.018 55 / 0.5)'}
            onMouseLeave={(e) => e.currentTarget.style.background = 'transparent'}
          >
            <span style={{
              width: 24, height: 24,
              flexShrink: 0,
              display: 'inline-block',
            }}>
              <window.LOF_Icons.FestivalIcon festival={f} size={24} />
            </span>
            <span className="t-display" style={{
              fontSize: 17,
              color: 'var(--paper)',
              lineHeight: 1.2,
            }}>{f.name}</span>
            <span className="t-serif" style={{
              fontSize: 12,
              fontStyle: 'italic',
              color: 'var(--paper-mute)',
              marginLeft: 'auto',
              flexShrink: 0,
            }}>{f.timeLabel}</span>
          </button>
        ))}
      </div>
    </div>
  );
}

function DidYouKnow({ fact }) {
  return (
    <div style={{
      padding: '12px 16px',
      background: 'oklch(0.18 0.016 50)',
      border: '1px solid oklch(0.30 0.020 55)',
      borderLeft: '2px solid var(--gold)',
      borderRadius: 4,
      flexShrink: 0,
      maxHeight: 110,
      overflow: 'hidden',
    }}>
      <div className="eyebrow" style={{
        color: 'var(--gold)',
        marginBottom: 4,
        fontSize: 10,
      }}>Did you know</div>
      <p
        key={fact}
        className="t-serif"
        style={{
          fontSize: 14,
          lineHeight: 1.45,
          fontStyle: 'italic',
          color: 'oklch(0.88 0.018 70)',
          animation: 'fadeUp 0.6s ease both',
          display: '-webkit-box',
          WebkitLineClamp: 4,
          WebkitBoxOrient: 'vertical',
          overflow: 'hidden',
        }}
      >{fact}</p>
    </div>
  );
}

function Timeline({ week, setWeek, festivalsByWeek }) {
  const trackRef = React.useRef(null);
  const draggingRef = React.useRef(false);
  const [hoverWeek, setHoverWeek] = React.useState(null);

  const setFromX = React.useCallback((clientX) => {
    const el = trackRef.current;
    if (!el) return;
    const rect = el.getBoundingClientRect();
    const ratio = Math.max(0, Math.min(1, (clientX - rect.left) / rect.width));
    const w = Math.max(1, Math.min(52, Math.round(ratio * 51 + 1)));
    setWeek(w);
  }, [setWeek]);

  const hoverFromX = React.useCallback((clientX) => {
    const el = trackRef.current;
    if (!el) return;
    const rect = el.getBoundingClientRect();
    const ratio = Math.max(0, Math.min(1, (clientX - rect.left) / rect.width));
    const w = Math.max(1, Math.min(52, Math.round(ratio * 51 + 1)));
    setHoverWeek(w);
  }, []);

  React.useEffect(() => {
    function onMove(e) {
      if (draggingRef.current) setFromX(e.clientX);
    }
    function onUp() { draggingRef.current = false; }
    window.addEventListener('mousemove', onMove);
    window.addEventListener('mouseup', onUp);
    window.addEventListener('touchend', onUp);
    return () => {
      window.removeEventListener('mousemove', onMove);
      window.removeEventListener('mouseup', onUp);
      window.removeEventListener('touchend', onUp);
    };
  }, [setFromX]);

  React.useEffect(() => {
    function onKey(e) {
      if (e.key === 'ArrowRight') { e.preventDefault(); setWeek(Math.min(52, week + 1)); }
      if (e.key === 'ArrowLeft')  { e.preventDefault(); setWeek(Math.max(1,  week - 1)); }
    }
    window.addEventListener('keydown', onKey);
    return () => window.removeEventListener('keydown', onKey);
  }, [week, setWeek]);

  const ratio = (week - 1) / 51;

  return (
    <div style={{
      position: 'relative',
      padding: '20px 56px 26px',
      background: 'linear-gradient(180deg, transparent, oklch(0.10 0.012 50 / 0.92) 35%, oklch(0.10 0.012 50) 100%)',
      backdropFilter: 'blur(8px)',
      WebkitBackdropFilter: 'blur(8px)',
      borderTop: '1px solid oklch(0.25 0.018 55)',
      animation: 'fadeUp 0.8s ease both',
      flexShrink: 0,
    }}>

      <div style={{
        display: 'grid',
        gridTemplateColumns: '12px repeat(12, 1fr) 12px',
        marginBottom: 14,
        alignItems: 'end',
      }}>
        <div />
        {MONTHS_SHORT.map((m, i) => {
          const mi = i + 1;
          const [a, b] = MW[mi];
          const active = week >= a && week <= b;
          const startThisMonth = () => setWeek(a);
          return (
            <button
              key={m}
              onClick={startThisMonth}
              style={{
                background: 'transparent',
                border: 'none',
                cursor: 'pointer',
                padding: '6px 4px',
                color: active ? 'var(--saffron)' : 'var(--paper-mute)',
                fontFamily: active ? 'Marcellus, serif' : 'Inter Tight, sans-serif',
                fontSize: active ? 18 : 13,
                letterSpacing: active ? '0.02em' : '0.12em',
                textTransform: active ? 'none' : 'uppercase',
                fontWeight: active ? 400 : 500,
                transition: 'color 200ms ease, font-size 200ms ease',
                position: 'relative',
                textAlign: 'left',
              }}
            >
              {active ? MONTHS_FULL[i] : m}
            </button>
          );
        })}
        <div />
      </div>

      <div
        ref={trackRef}
        onMouseDown={(e) => { draggingRef.current = true; setFromX(e.clientX); }}
        onMouseMove={(e) => hoverFromX(e.clientX)}
        onMouseLeave={() => setHoverWeek(null)}
        onTouchStart={(e) => { draggingRef.current = true; setFromX(e.touches[0].clientX); }}
        onTouchMove={(e) => setFromX(e.touches[0].clientX)}
        style={{
          position: 'relative',
          height: 56,
          cursor: 'pointer',
          userSelect: 'none',
          touchAction: 'none',
        }}
      >
        <div style={{
          position: 'absolute',
          left: 0, right: 0, top: 28,
          height: 1,
          background: 'oklch(0.35 0.02 55)',
        }} />

        <div style={{
          position: 'absolute',
          left: 0, top: 27,
          height: 3,
          width: `${ratio * 100}%`,
          background: 'linear-gradient(90deg, oklch(0.62 0.165 28), oklch(0.78 0.155 65), oklch(0.84 0.135 88))',
          borderRadius: 2,
          boxShadow: '0 0 12px oklch(0.78 0.155 65 / 0.55)',
        }} />

        {Array.from({ length: 52 }, (_, i) => {
          const w = i + 1;
          const x = (i / 51) * 100;
          const isMajor = [1,5,9,14,18,22,27,31,35,40,44,48].includes(w);
          const hasFest = (festivalsByWeek[w] || 0) > 0;
          const count = festivalsByWeek[w] || 0;
          const isActive = w === week;
          return (
            <React.Fragment key={w}>
              <div style={{
                position: 'absolute',
                left: `calc(${x}% )`,
                top: isMajor ? 18 : 22,
                width: 1,
                height: isMajor ? 18 : 10,
                background: isActive ? 'var(--saffron)' : (hasFest ? 'oklch(0.55 0.04 65)' : 'oklch(0.35 0.018 55)'),
                transform: 'translateX(-0.5px)',
              }} />
              {hasFest && (
                <div style={{
                  position: 'absolute',
                  left: `calc(${x}% )`,
                  top: 10 - Math.min(count, 8),
                  width: 3,
                  height: 3 + Math.min(count, 8),
                  background: 'oklch(0.78 0.155 65)',
                  opacity: 0.4 + Math.min(count, 8) * 0.07,
                  borderRadius: 2,
                  transform: 'translateX(-1.5px)',
                  boxShadow: count > 4 ? '0 0 4px oklch(0.78 0.155 65 / 0.7)' : 'none',
                }} />
              )}
            </React.Fragment>
          );
        })}

        <div style={{
          position: 'absolute',
          left: `${ratio * 100}%`,
          top: 8,
          width: 0,
          transform: 'translateX(-50%)',
          pointerEvents: 'none',
        }}>
          <div style={{
            width: 22, height: 22,
            borderRadius: '50%',
            background: 'radial-gradient(circle, oklch(0.95 0.10 80), oklch(0.78 0.155 65) 60%, oklch(0.55 0.14 35))',
            border: '2px solid oklch(0.96 0.03 80)',
            boxShadow: '0 0 0 4px oklch(0.78 0.155 65 / 0.18), 0 0 20px oklch(0.78 0.155 65 / 0.6)',
            margin: '0 auto',
          }} />
          <div style={{
            width: 1,
            height: 26,
            background: 'linear-gradient(180deg, oklch(0.78 0.155 65), transparent)',
            margin: '2px auto 0',
            opacity: 0.6,
          }} />
        </div>

        {hoverWeek && hoverWeek !== week && (
          <div style={{
            position: 'absolute',
            left: `${((hoverWeek - 1) / 51) * 100}%`,
            top: -8,
            transform: 'translate(-50%, -100%)',
            background: 'oklch(0.20 0.018 55)',
            border: '1px solid oklch(0.40 0.02 55)',
            padding: '4px 10px',
            borderRadius: 3,
            fontSize: 11,
            color: 'var(--paper-mute)',
            fontFamily: 'JetBrains Mono, ui-monospace, monospace',
            letterSpacing: '0.08em',
            pointerEvents: 'none',
            whiteSpace: 'nowrap',
          }}>
            {MONTHS_SHORT[weekToMonth(hoverWeek).month - 1]} · W{weekToMonth(hoverWeek).weekInMonth}
            {festivalsByWeek[hoverWeek] ? ` · ${festivalsByWeek[hoverWeek]} fest` : ''}
          </div>
        )}
      </div>

      <div style={{
        display: 'flex',
        justifyContent: 'space-between',
        marginTop: 8,
        gap: 16,
      }}>
        <div className="eyebrow" style={{ fontSize: 10, color: 'var(--paper-mute)' }}>
          Drag the pointer · or use ← →
        </div>
        <div className="eyebrow" style={{ fontSize: 10, color: 'var(--paper-mute)' }}>
          Click a month to leap · click a pin for the story
        </div>
      </div>
    </div>
  );
}

Object.assign(window, {
  Header, SidePanel, Timeline,
  MONTHS_FULL, MONTHS_SHORT, MW, weekToMonth,
});
