
// shared.jsx — Shared UI components
const { useState } = React;
const { useApp } = window;

function CozyCard({ children, className = '', style = {}, active = false, onClick }) {
  return (
    <div
      className={`cozy-card ${active ? 'active-card' : ''} ${className}`}
      style={style}
      onClick={onClick}
    >
      <div className="corner-dot corner-dot-bl"></div>
      <div className="corner-dot corner-dot-br"></div>
      {children}
    </div>
  );
}

function CozyButton({ children, onClick, color = 'sage', small = false, className = '', disabled = false, style = {} }) {
  const palettes = {
    sage:       { bg: 'var(--accent-green)', text: '#fff',                  shadow: 'rgba(0,0,0,0.2)' },
    terracotta: { bg: 'var(--accent-orange)', text: '#fff',                 shadow: 'rgba(0,0,0,0.2)' },
    pink:       { bg: '#F2A7C3',             text: 'var(--text-on-light-pastel)', shadow: 'rgba(0,0,0,0.2)' },
    lavender:   { bg: '#C5B4E3',             text: 'var(--text-on-light-pastel)', shadow: 'rgba(0,0,0,0.2)' },
    yellow:     { bg: '#F7DFA0',             text: 'var(--text-on-light-pastel)', shadow: 'rgba(0,0,0,0.2)' },
    cream:      { bg: 'var(--surface-card)', text: 'var(--text-primary)',         shadow: 'var(--border-default)', border: '2px solid var(--border-emphasis)' },
    red:        { bg: '#F2A7A7',             text: 'var(--text-on-light-pastel)', shadow: 'rgba(0,0,0,0.2)' },
    amber:      { bg: '#E89818',             text: '#fff',                  shadow: 'rgba(0,0,0,0.2)' },
  };
  const c = palettes[color] || palettes.sage;
  return (
    <button
      disabled={disabled}
      onClick={onClick}
      className={`cozy-btn ${className}`}
      style={{
        background: c.bg, color: c.text,
        border: c.border || 'none',
        borderRadius: small ? 12 : 16,
        padding: small ? '4px 12px' : '8px 20px',
        fontSize: small ? 12 : 14,
        fontFamily: 'Nunito, sans-serif', fontWeight: 800,
        boxShadow: `0 3px 0 ${c.shadow}`,
        cursor: disabled ? 'not-allowed' : 'pointer',
        opacity: disabled ? 0.6 : 1,
        display: 'inline-flex', alignItems: 'center', gap: 6,
        ...style,
      }}
    >
      {children}
    </button>
  );
}

function StarRating({ value = 1, max = 4, onChange, size = 14 }) {
  const stars = Array.from({ length: max }, (_, idx) => idx + 1);
  return (
    <div style={{ display: 'flex', gap: 1, alignItems: 'center' }}>
      {stars.map(i => (
        <span
          key={i}
          onClick={(e) => {
            if (onChange) {
              e.stopPropagation();
              onChange(i === value && value > 1 ? i - 1 : i);
            }
          }}
          style={{
            fontSize: size, cursor: onChange ? 'pointer' : 'default',
            color: i <= value ? '#F59E0B' : 'var(--border-default)',
            textShadow: i <= value ? '0 1px 2px rgba(0,0,0,0.4)' : 'none',
            transition: 'all 0.15s',
            userSelect: 'none',
            lineHeight: 1,
          }}
        >★</span>
      ))}
    </div>
  );
}

function PositionBadge({ position, small = false }) {
  const emojis = window.POSITION_EMOJIS;
  const colors = window.POSITION_COLORS;
  return (
    <span style={{
      background: colors[position] || '#F7DFA0',
      border: '1.5px solid var(--border-default)',
      borderRadius: 20, padding: small ? '1px 8px' : '3px 12px',
      fontSize: small ? 11 : 12, fontWeight: 800,
      fontFamily: 'Nunito, sans-serif', color: 'var(--text-on-light)',
      whiteSpace: 'nowrap',
    }}>
      {emojis[position]} {position}
    </span>
  );
}

function getSlotChampionId(val) {
  if (!val) return null;
  if (typeof val === 'string') return val;
  if (typeof val === 'object') {
    const raw = val.championId !== undefined ? val.championId : val.starter;
    if (typeof raw === 'string') return raw;
    if (typeof raw === 'object' && raw) return getSlotChampionId(raw);
    return null;
  }
  return null;
}

function getSlotAlternates(val) {
  if (!val || typeof val === 'string') return [];
  if (typeof val === 'object') {
    if (Array.isArray(val.alternates)) {
      return val.alternates.filter(Boolean);
    }
    if (val.alternates && typeof val.alternates === 'object') {
      return Object.values(val.alternates).filter(Boolean);
    }
  }
  return [];
}

function normalizeRoleSlot(val) {
  return {
    championId: getSlotChampionId(val),
    alternates: getSlotAlternates(val).slice(0, 4),
  };
}

function promoteAlternateToStarter(slot, altId) {
  const currentSlot = normalizeRoleSlot(slot);
  const oldPrimary = currentSlot.championId;
  const oldAlts = [...currentSlot.alternates];
  const altIdx = oldAlts.indexOf(altId);
  if (altIdx === -1) return currentSlot;

  const newAlts = [...oldAlts];
  if (oldPrimary) {
    newAlts[altIdx] = oldPrimary;
  } else {
    newAlts.splice(altIdx, 1);
  }

  return {
    championId: altId,
    alternates: newAlts,
  };
}

function removeStarterFromSlot(slot) {
  const currentSlot = normalizeRoleSlot(slot);
  if (currentSlot.alternates.length > 0) {
    const [firstAlt, ...restAlts] = currentSlot.alternates;
    return {
      championId: firstAlt,
      alternates: restAlts,
    };
  }
  return {
    championId: null,
    alternates: [],
  };
}

function ChampionIcon({ championId, size = 52, style = {}, noAnim = false }) {
  const { championIconUrl } = useApp();
  const [err, setErr] = useState(false);
  const numericSize = parseFloat(size);
  const radius = isNaN(numericSize) ? 11 : Math.round(numericSize * 0.22);
  const fontSize = isNaN(numericSize) ? 20 : numericSize * 0.38;

  const resolvedId = getSlotChampionId(championId);

  if (!resolvedId) return (
    <div style={{
      width: size, height: size, borderRadius: radius,
      border: '2px dashed var(--border-default)',
      display: 'flex', alignItems: 'center', justifyContent: 'center',
      background: 'var(--surface-nested)', fontSize: fontSize, color: 'var(--text-muted)',
      flexShrink: 0, ...style,
    }}>＋</div>
  );

  return (
    <div
      className={noAnim ? '' : 'champion-sticker'}
      style={{
        width: size, height: size, borderRadius: radius,
        overflow: 'hidden', border: '2px solid var(--border-emphasis)',
        background: 'var(--surface-nested)', flexShrink: 0, ...style,
      }}
    >
      {err ? (
        <div style={{
          width: '100%', height: '100%', display: 'flex',
          alignItems: 'center', justifyContent: 'center',
          fontSize: 10, color: 'var(--accent-orange)', fontFamily: 'Nunito', fontWeight: 700,
          textAlign: 'center', padding: 2,
        }}>{typeof resolvedId === 'string' ? resolvedId.slice(0, 4) : ''}</div>
      ) : (
        <img
          src={championIconUrl(resolvedId)}
          alt={resolvedId}
          style={{ width: '100%', height: '100%', objectFit: 'cover' }}
          onError={() => setErr(true)}
        />
      )}
    </div>
  );
}

function LoadingSpinner() {
  return (
    <div style={{ display: 'flex', flexDirection: 'column', alignItems: 'center', justifyContent: 'center', height: '60vh', gap: 16 }}>
      <div className="float" style={{ fontSize: 52 }}>🌸</div>
      <div className="spin" style={{ width: 44, height: 44, border: '4px solid var(--border-default)', borderTop: '4px solid var(--accent-orange)', borderRadius: '50%' }}></div>
      <p className="fredoka" style={{ color: 'var(--accent-orange)', fontSize: 22, margin: 0 }}>Loading champion stickers…</p>
      <p style={{ color: 'var(--text-muted)', fontSize: 14, margin: 0 }}>Fetching from Riot Data Dragon 🐉</p>
    </div>
  );
}

function Toast({ message }) {
  if (!message) return null;
  return (
    <div className="toast" style={{
      position: 'fixed', bottom: 96, left: '50%', transform: 'translateX(-50%)',
      background: 'var(--surface-modal)', color: 'var(--text-primary)', border: '1.5px solid var(--border-emphasis)', borderRadius: 20,
      padding: '10px 24px', fontFamily: 'Nunito', fontWeight: 800, fontSize: 15,
      zIndex: 9999, boxShadow: '0 8px 32px var(--border-default)', whiteSpace: 'nowrap',
    }}>
      {message}
    </div>
  );
}

function StatBar({ label, value, color = '#7CBF8E' }) {
  return (
    <div style={{ marginBottom: 8 }}>
      <div style={{ display: 'flex', justifyContent: 'space-between', fontSize: 13, fontWeight: 700, marginBottom: 4, color: 'var(--text-primary)' }}>
        <span>{label}</span>
        <span style={{ color: 'var(--accent-orange)' }}>{value}%</span>
      </div>
      <div style={{ height: 12, background: 'var(--surface-nested)', borderRadius: 20, overflow: 'hidden', border: '1.5px solid var(--border-default)' }}>
        <div style={{
          height: '100%', width: `${value}%`, background: color,
          borderRadius: 20, transition: 'width 0.6s cubic-bezier(0.34, 1.2, 0.64, 1)',
        }}></div>
      </div>
    </div>
  );
}

function SectionTitle({ children, emoji }) {
  return (
    <h2 className="fredoka" style={{ color: 'var(--accent-orange)', fontSize: 22, margin: '0 0 12px 0', display: 'flex', alignItems: 'center', gap: 8 }}>
      {emoji && <span>{emoji}</span>}
      {children}
    </h2>
  );
}

function Tag({ children, color = 'green' }) {
  const c = {
    green: { bg: '#B8E0C0', border: '#7CBF8E', text: '#2d6b47' },
    pink:  { bg: '#F9D0E0', border: '#F2A7C3', text: '#8b3a5a' },
    red:   { bg: '#F9D0D0', border: '#E8A0A0', text: '#8b3a3a' },
  }[color] || { bg: '#B8E0C0', border: '#7CBF8E', text: '#2d6b47' };
  return (
    <span style={{
      background: c.bg, border: `1.5px solid ${c.border}`,
      borderRadius: 20, padding: '3px 12px',
      fontSize: 13, fontWeight: 700, color: c.text,
      fontFamily: 'Nunito, sans-serif',
      display: 'inline-flex', alignItems: 'center', gap: 4,
    }}>{children}</span>
  );
}


function useDebounceFirebaseUpdate(remoteValue, onSave, delay = 800) {
  const [localValue, setLocalValue] = React.useState(remoteValue);
  const isFocusedRef = React.useRef(false);
  const timerRef = React.useRef(null);
  const onSaveRef = React.useRef(onSave);
  const localValueRef = React.useRef(localValue);

  React.useEffect(() => {
    onSaveRef.current = onSave;
  }, [onSave]);

  React.useEffect(() => {
    localValueRef.current = localValue;
  }, [localValue]);

  // Sync remote changes into local state if NOT focused
  React.useEffect(() => {
    if (!isFocusedRef.current) {
      setLocalValue(remoteValue);
    }
  }, [remoteValue]);

  // Cleanup timer and save pending changes on unmount
  React.useEffect(() => {
    return () => {
      if (timerRef.current) {
        clearTimeout(timerRef.current);
        onSaveRef.current(localValueRef.current);
      }
    };
  }, []);

  const triggerSave = React.useCallback((value) => {
    if (timerRef.current) {
      clearTimeout(timerRef.current);
      timerRef.current = null;
    }
    onSaveRef.current(value);
  }, []);

  const handleChange = React.useCallback((newValue) => {
    setLocalValue(newValue);
    if (timerRef.current) clearTimeout(timerRef.current);
    timerRef.current = setTimeout(() => {
      triggerSave(newValue);
    }, delay);
  }, [delay, triggerSave]);

  const handleBlur = React.useCallback(() => {
    isFocusedRef.current = false;
    triggerSave(localValueRef.current);
  }, [triggerSave]);

  const handleFocus = React.useCallback(() => {
    isFocusedRef.current = true;
  }, []);

  return {
    value: localValue,
    setValue: setLocalValue,
    onChange: handleChange,
    onBlur: handleBlur,
    onFocus: handleFocus,
    isFocused: isFocusedRef.current,
  };
}

function ComfortBadge({ comfort = 1, style = {} }) {
  const levels = {
    1: { label: 'Learning',    bg: '#B8E0C0', border: '#7CBF8E', text: '#2d6b47' },
    2: { label: 'Comfortable', bg: '#F7DFA0', border: '#c8ae65', text: '#6b5420' },
    3: { label: 'Confident',   bg: '#C5B4E3', border: '#9e87cc', text: '#4a2d8b' },
    4: { label: 'Ready',       bg: '#AED6F1', border: '#5b9abf', text: '#1b4f72' },
  };
  const c = levels[comfort] || levels[1];
  return (
    <span style={{
      background: c.bg,
      border: `1.5px solid ${c.border}`,
      borderRadius: 14,
      padding: '1px 8px',
      fontSize: 10,
      fontWeight: 800,
      fontFamily: 'Nunito, sans-serif',
      color: c.text,
      display: 'inline-flex',
      alignItems: 'center',
      gap: 4,
      ...style,
    }}>
      {c.label}
    </span>
  );
}

const FILTER_TAGS = ['All', 'Tank', 'Fighter', 'Mage', 'Assassin', 'Marksman', 'Support'];
const FILTER_EMOJIS = { All: '🌟', Tank: '🛡️', Fighter: '💪', Mage: '🔮', Assassin: '🗡️', Marksman: '🏹', Support: '💛' };

function normalizeSearchText(str) {
  if (!str) return '';
  return String(str)
    .normalize('NFD')
    .replace(/[\u0300-\u036f]/g, '')
    .toLowerCase()
    .replace(/[^a-z0-9]/g, '');
}

function matchesChampionSearch(champ, query) {
  if (!query || !query.trim()) return true;
  if (!champ) return false;

  const rawQ = query.trim().toLowerCase();
  const name = champ.name || champ.championId || champ.id || '';
  const id = champ.id || champ.championId || '';

  const rawName = String(name).toLowerCase();
  const rawId = String(id).toLowerCase();

  // 1. Direct substring match
  if (rawName.includes(rawQ) || rawId.includes(rawQ)) return true;

  // 2. Normalized match (ignores punctuation like ', ., -, spaces, accents)
  const cleanQ = normalizeSearchText(query);
  if (!cleanQ) return false;

  const cleanName = normalizeSearchText(name);
  const cleanId = normalizeSearchText(id);

  return cleanName.includes(cleanQ) || cleanId.includes(cleanQ);
}

function ChampionSearchModal({
  isOpen,
  onClose,
  title = "Select Champion",
  subtitle = "",
  onSelect,
  excludeChampionIds = [],
}) {
  const { champions } = window.useApp ? window.useApp() : {};
  const [search, setSearch] = React.useState('');
  const [filterTag, setFilterTag] = React.useState('All');
  const searchInputRef = React.useRef(null);

  React.useEffect(() => {
    if (isOpen) {
      setSearch('');
      setFilterTag('All');
      const t = setTimeout(() => {
        if (searchInputRef.current) searchInputRef.current.focus();
      }, 50);
      return () => clearTimeout(t);
    }
  }, [isOpen]);

  const excludeSet = React.useMemo(() => new Set(excludeChampionIds || []), [excludeChampionIds]);

  const champList = React.useMemo(() => {
    const list = Object.values(champions || {});
    return list
      .filter(c => !excludeSet.has(c.id))
      .filter(c => filterTag === 'All' || (c.tags && c.tags.includes(filterTag)))
      .filter(c => matchesChampionSearch(c, search))
      .sort((a, b) => a.name.localeCompare(b.name));
  }, [champions, excludeSet, filterTag, search]);

  if (!isOpen) return null;

  return (
    <div
      onClick={onClose}
      style={{
        position: 'fixed', inset: 0,
        background: 'rgba(74, 55, 40, 0.65)', backdropFilter: 'blur(3px)',
        zIndex: 1000, display: 'flex', alignItems: 'center',
        justifyContent: 'center', padding: 16,
      }}
    >
      <div
        onClick={e => e.stopPropagation()}
        className="cozy-card pop-in"
        style={{
          width: '100%', maxWidth: 520, maxHeight: '85vh',
          display: 'flex', flexDirection: 'column', padding: 18,
          background: 'var(--surface-modal)', boxSizing: 'border-box',
        }}
      >
        {/* Modal Header */}
        <div style={{
          display: 'flex', alignItems: 'center', justifyContent: 'space-between',
          marginBottom: 12, borderBottom: '1.5px solid var(--border-default)', paddingBottom: 10,
        }}>
          <div>
            <div className="fredoka" style={{ color: 'var(--accent-orange)', fontSize: 18 }}>
              🔍 {title}
            </div>
            {subtitle && (
              <div style={{ fontSize: 11, fontWeight: 700, color: 'var(--text-muted)', marginTop: 2 }}>
                {subtitle}
              </div>
            )}
          </div>
          <button
            onClick={onClose}
            className="cozy-btn"
            style={{
              background: 'var(--surface-nested)', border: '2px solid var(--border-default)',
              borderRadius: '50%', width: 30, height: 30,
              fontSize: 14, fontWeight: 800, color: 'var(--accent-orange)',
              cursor: 'pointer', display: 'flex', alignItems: 'center', justifyContent: 'center',
            }}
          >
            ✕
          </button>
        </div>

        {/* Search */}
        <input
          ref={searchInputRef}
          value={search}
          onChange={e => setSearch(e.target.value)}
          placeholder="Search champions…"
          style={{
            width: '100%', padding: '8px 12px',
            border: '2px solid var(--border-default)', borderRadius: 12,
            fontFamily: 'Nunito', fontSize: 13, fontWeight: 600,
            background: 'var(--surface-nested)', color: 'var(--text-primary)', outline: 'none',
            boxSizing: 'border-box', marginBottom: 10,
          }}
        />

        {/* Filter chips */}
        <div style={{ display: 'flex', gap: 4, flexWrap: 'wrap', marginBottom: 12 }}>
          {FILTER_TAGS.map(tag => (
            <button key={tag} onClick={() => setFilterTag(tag)} className="cozy-btn" style={{
              background: filterTag === tag ? 'var(--accent-orange)' : 'var(--surface-nested)',
              color: filterTag === tag ? 'white' : 'var(--text-primary)',
              border: '2px solid var(--border-default)', borderRadius: 16,
              padding: '3px 10px', fontSize: 11, fontWeight: 800,
              fontFamily: 'Nunito', cursor: 'pointer',
            }}>
              {FILTER_EMOJIS[tag]} {tag}
            </button>
          ))}
        </div>

        {/* Champion icon grid */}
        <div style={{
          display: 'grid', gridTemplateColumns: 'repeat(auto-fill, minmax(56px, 1fr))',
          gap: 8, overflowY: 'auto', flex: 1, minHeight: 0, paddingRight: 4, paddingBottom: 4,
          WebkitOverflowScrolling: 'touch',
        }}>
          {champList.map(champ => (
            <div
              key={champ.id}
              onClick={() => {
                onSelect(champ.id);
                onClose();
              }}
              title={champ.name}
              style={{
                display: 'flex', flexDirection: 'column', alignItems: 'center',
                gap: 3, cursor: 'pointer',
                transition: 'all 0.2s cubic-bezier(0.34, 1.56, 0.64, 1)',
                position: 'relative',
              }}
              className="champion-sticker"
            >
              <window.ChampionIcon championId={champ.id} size={50} noAnim />
              <span style={{
                fontSize: 10, fontWeight: 700, color: 'var(--text-primary)',
                textAlign: 'center', lineHeight: 1.2,
                maxWidth: 56, overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap',
              }}>
                {champ.name}
              </span>
            </div>
          ))}
          {champList.length === 0 && (
            <div style={{ gridColumn: '1 / -1', textAlign: 'center', color: 'var(--text-muted)', fontWeight: 700, fontSize: 13, padding: 24 }}>
              No champions found 🌱
            </div>
          )}
        </div>
      </div>
    </div>
  );
}

Object.assign(window, { CozyCard, CozyButton, StarRating, PositionBadge, ChampionIcon, LoadingSpinner, Toast, StatBar, SectionTitle, Tag, ComfortBadge, useDebounceFirebaseUpdate, FILTER_TAGS, FILTER_EMOJIS, getSlotChampionId, getSlotAlternates, normalizeRoleSlot, promoteAlternateToStarter, removeStarterFromSlot, ChampionSearchModal, normalizeSearchText, matchesChampionSearch });

