// dashboard-widgets.jsx — draggable, resizable widget system for the dashboard.
// Each widget has: id, size (s/m/l), visible, order. Persisted via tweak system.

const WIDGET_SIZES = {
  s: { cols: 4, rows: 1 },
  m: { cols: 6, rows: 1 },
  l: { cols: 12, rows: 1 },
};

const DEFAULT_LAYOUT = [
  { id: 'mascot',  size: 's', visible: true },
  { id: 'xp',      size: 's', visible: true },
  { id: 'streak',  size: 's', visible: true },
  { id: 'focus',   size: 'm', visible: true },
  { id: 'today',   size: 'm', visible: true },
  { id: 'zones',   size: 'l', visible: true },
  { id: 'wheel',   size: 'm', visible: true },
  { id: 'leader',  size: 'm', visible: true },
  { id: 'feed',    size: 'm', visible: true },
  { id: 'badges',  size: 'm', visible: true },
];

const WIDGET_META = {
  mascot:  { title: 'Маскот',          icon: '🌱' },
  xp:      { title: 'XP и уровень',    icon: '⚡' },
  streak:  { title: 'Серия',           icon: '🔥' },
  zones:   { title: '8 зон жизни',     icon: '🎯' },
  today:   { title: 'Привычки сегодня', icon: '✓' },
  focus:   { title: 'Фокус недели',    icon: '⭐' },
  wheel:   { title: 'Колесо баланса',  icon: '🎡' },
  leader:  { title: 'Рейтинг недели',  icon: '🏆' },
  feed:    { title: 'Активность',      icon: '⚙' },
  badges:  { title: 'Бейджи',          icon: '🏅' },
};

// ── injected widget CSS ────────────────────────────────────────
const __WIDGET_CSS = `
.dash-grid {
  display: grid;
  grid-template-columns: repeat(12, 1fr);
  gap: 14px;
  position: relative;
}
.widget {
  position: relative;
  background: var(--bg-card);
  border: 1px solid var(--border);
  border-radius: var(--r-lg);
  padding: 14px;
  box-shadow: var(--shadow-card);
  transition: opacity 200ms, transform 200ms, box-shadow 200ms, border-color 200ms;
  display: flex;
  flex-direction: column;
  min-width: 0;
  min-height: 140px;
  animation: widget-in 360ms cubic-bezier(0.34, 1.56, 0.64, 1);
}
@keyframes widget-in {
  from { opacity: 0; transform: translateY(8px) scale(0.96); }
  to   { opacity: 1; transform: none; }
}
.widget[data-size="s"]  { grid-column: span 4;  }
.widget[data-size="m"]  { grid-column: span 6;  }
.widget[data-size="l"]  { grid-column: span 12; }
.widget.dragging   { opacity: 0.35; transform: scale(0.96); cursor: grabbing; }
.widget.drag-target { box-shadow: 0 0 0 2px var(--accent), 0 0 calc(20px * var(--glow-mult)) var(--accent-ring); }
.widget:hover .widget-chrome { opacity: 1; }
.widget-chrome {
  position: absolute; top: 8px; right: 8px;
  display: flex; gap: 4px; align-items: center;
  background: color-mix(in oklab, var(--bg-card) 92%, transparent);
  backdrop-filter: blur(6px);
  border-radius: var(--r-md);
  padding: 4px;
  border: 1px solid var(--border-subtle);
  opacity: 0;
  transition: opacity 160ms;
  z-index: 4;
}
.widget-edit .widget-chrome { opacity: 1; }
.widget-edit .widget { animation: widget-wiggle 0.6s ease-in-out infinite; }
@keyframes widget-wiggle {
  0%, 100% { transform: rotate(0deg); }
  25% { transform: rotate(-0.4deg); }
  75% { transform: rotate(0.4deg); }
}
.widget-chrome button {
  width: 22px; height: 22px;
  display: grid; place-items: center;
  border-radius: 5px;
  color: var(--text-tertiary);
  font-size: 11px;
  font-family: var(--font-mono);
}
.widget-chrome button:hover { background: var(--bg-card-hover); color: var(--text-primary); }
.widget-chrome button.active { background: var(--accent-soft); color: var(--accent-2); }
.widget-handle {
  cursor: grab;
  user-select: none;
}
.widget-handle:active { cursor: grabbing; }
.widget-head {
  display: flex; align-items: center; gap: 8px;
  margin-bottom: 10px;
  font-family: var(--font-display);
  font-weight: 700;
  font-size: 14px;
  letter-spacing: -0.01em;
}
.widget-head .ico {
  width: 22px; height: 22px;
  display: grid; place-items: center;
  border-radius: 5px;
  background: var(--accent-soft);
  font-size: 12px;
}
.widget-head .menu {
  margin-left: auto;
  color: var(--text-tertiary);
  font-size: 11px;
  font-family: var(--font-mono);
  text-transform: uppercase;
  letter-spacing: 0.06em;
}
.widget-add {
  position: relative;
  border: 1.5px dashed var(--border);
  border-radius: var(--r-lg);
  color: var(--text-tertiary);
  display: flex; align-items: center; justify-content: center;
  gap: 8px; padding: 14px;
  font-size: 12.5px; font-family: var(--font-body);
  cursor: pointer;
  transition: color 160ms, border-color 160ms, background 160ms;
  min-height: 140px;
}
.widget-add:hover { color: var(--accent-2); border-color: var(--accent); background: var(--accent-soft); }
.dash-toolbar {
  display: flex; align-items: center; gap: 8px;
  margin-bottom: 14px;
  padding: 8px 10px;
  background: var(--bg-app-2);
  border: 1px solid var(--border-subtle);
  border-radius: var(--r-md);
  font-size: 12px;
  color: var(--text-secondary);
}
.dash-toolbar .pill {
  font-family: var(--font-mono); font-size: 11px;
  padding: 2px 8px; border-radius: 9999px;
  background: var(--accent-soft); color: var(--accent-2);
  letter-spacing: 0.06em; text-transform: uppercase;
}
.add-overlay {
  position: fixed; inset: 0; z-index: 200;
  display: grid; place-items: center;
  background: rgba(0,0,0,0.5); backdrop-filter: blur(6px);
  animation: fade-in 200ms;
}
.add-overlay .panel {
  background: var(--bg-card);
  border: 1px solid var(--border);
  border-radius: var(--r-xl);
  padding: 24px;
  width: 460px;
  box-shadow: var(--shadow-pop);
}
`;
if (typeof document !== 'undefined' && !document.getElementById('widget-css')) {
  const s = document.createElement('style');
  s.id = 'widget-css';
  s.textContent = __WIDGET_CSS;
  document.head.appendChild(s);
}

// ── Widget body components ────────────────────────────────────

function WMascot({ state, dispatch }) {
  return (
    <div style={{ flex: 1, display: 'flex', alignItems: 'center', justifyContent: 'center', flexDirection: 'column', gap: 6, minHeight: 160 }}>
      <Mascot id={state.mascotId} emotion={state.mascotEmotion} size={120} level={ME.level} sparkle aura />
      <div style={{ fontFamily: 'var(--font-display)', fontWeight: 700, fontSize: 13, marginTop: 4 }}>
        {MASCOT_BY_ID[state.mascotId]?.name}
      </div>
      <div className="dim mono" style={{ fontSize: 10.5, textAlign: 'center', maxWidth: 180 }}>
        {state.mascotEmotion === 'celebrate' && '🎉 Поздравляет с прогрессом!'}
        {state.mascotEmotion === 'excited'   && 'Рад каждому шагу'}
        {state.mascotEmotion === 'focus'     && 'Медитирует вместе с тобой'}
        {state.mascotEmotion === 'sleepy'    && 'Дремлет, разбуди отметкой'}
        {state.mascotEmotion === 'idle'      && 'Спокойно ждёт твоего следующего шага'}
      </div>
    </div>
  );
}

function WXP() {
  return <XPBar />;
}

function WStreak({ state }) {
  const longest = Math.max(...state.habits.map(h => h.longest));
  return (
    <div style={{ flex: 1, display: 'flex', flexDirection: 'column', justifyContent: 'center', gap: 6 }}>
      <div style={{ display: 'flex', alignItems: 'baseline', gap: 8 }}>
        <span style={{ fontSize: 28, color: 'var(--gold)' }}><Icon.fire /></span>
        <NumberTicker value={23} className="mono" style={{ fontSize: 38, fontWeight: 800, color: 'var(--gold)', fontFamily: 'var(--font-mono)', letterSpacing: '-0.04em', lineHeight: 1 }} />
        <span className="dim" style={{ fontSize: 13 }}>дней подряд</span>
      </div>
      <div className="dim" style={{ fontSize: 12 }}>
        Рекорд: <b className="mono" style={{ color: 'var(--text-primary)' }}>{longest}</b> · Free pass: <b style={{ color: 'var(--success)' }}>1/1</b>
      </div>
    </div>
  );
}

function WZones({ state }) {
  return (
    <div style={{ display: 'grid', gridTemplateColumns: 'repeat(4, 1fr)', gap: 10 }}>
      {ZONES.map(z => {
        const score = state.wheel.current[z.id];
        const target = state.wheel.target[z.id];
        const wishCount = state.wishes.filter(w => w.zone === z.id && w.status !== 'done').length;
        return (
          <div key={z.id} className={`zone-tile ${z.cls}`} style={{ padding: 11 }}>
            <div className="head" style={{ marginBottom: 8 }}>
              <div className="glyph" style={{ width: 30, height: 30, fontSize: 13 }}>{z.icon}</div>
              <div style={{ flex: 1, minWidth: 0 }}>
                <div className="nm" style={{ fontSize: 12.5 }}>{z.name}</div>
                <div className="ct" style={{ fontSize: 10 }}>{wishCount} желани{wishCount === 1 ? 'е' : 'й'}</div>
              </div>
            </div>
            <div className="row" style={{ gap: 10 }}>
              <ProgressRing value={score / 10} size={44} stroke={4} color={z.color} label={score} sub={`/${target}`} />
              <div style={{ flex: 1, minWidth: 0 }}>
                <div style={{ height: 4, background: 'var(--border)', borderRadius: 2 }}>
                  <div style={{ width: `${(score / target) * 100}%`, height: '100%', background: z.color, borderRadius: 2, transition: 'width 600ms cubic-bezier(0.22, 1, 0.36, 1)' }} />
                </div>
                <div className="mono" style={{ fontSize: 10, color: 'var(--text-tertiary)', marginTop: 4 }}>Δ +{(target - score).toFixed(0)}</div>
              </div>
            </div>
          </div>
        );
      })}
    </div>
  );
}

function WToday({ state, dispatch }) {
  const habits = state.habits;
  const done = habits.filter(h => h.doneToday).length;
  return (
    <div style={{ flex: 1, display: 'flex', flexDirection: 'column' }}>
      <div className="spread mb-3">
        <span className="dim mono" style={{ fontSize: 11 }}>{done} / {habits.length} выполнено</span>
        <div style={{ height: 4, width: 100, background: 'var(--border)', borderRadius: 2 }}>
          <div style={{ width: `${(done / habits.length) * 100}%`, height: '100%', background: 'var(--success)', borderRadius: 2, transition: 'width 400ms' }} />
        </div>
      </div>
      <div className="col" style={{ gap: 4, flex: 1 }}>
        {habits.map(h => {
          const z = ZONE_BY_ID[h.zone];
          return (
            <div key={h.id} className={`row ${z.cls}`}
                 onClick={() => dispatch('toggleHabit', h.id)}
                 style={{ padding: '7px 4px', gap: 10, cursor: 'pointer', borderRadius: 'var(--r-sm)', transition: 'background 120ms' }}>
              <button className={`check-btn ${h.doneToday ? 'done' : ''}`} style={{ width: 22, height: 22 }}>
                {h.doneToday && <Icon.check />}
              </button>
              <span style={{ flex: 1, fontSize: 13, fontWeight: h.doneToday ? 400 : 500, textDecoration: h.doneToday ? 'line-through' : 'none', color: h.doneToday ? 'var(--text-tertiary)' : undefined }}>
                {h.title}
              </span>
              <span className="mono" style={{ fontSize: 11, color: 'var(--gold)' }}>
                <Icon.fire style={{ verticalAlign: '-2px' }} /> {h.streak}
              </span>
            </div>
          );
        })}
      </div>
    </div>
  );
}

function WFocus({ state }) {
  const items = [state.wishes[0], state.wishes[7], state.wishes[12]];
  return (
    <div className="col" style={{ gap: 6, flex: 1 }}>
      {items.map(w => {
        const z = ZONE_BY_ID[w.zone];
        const pct = w.steps_total ? w.steps_done / w.steps_total : 0;
        return (
          <div key={w.id} className={`mini-wish ${z.cls}`} style={{ padding: '8px 10px' }}>
            <span style={{ fontSize: 16 }}>{w.cover}</span>
            <span style={{ flex: 1, fontSize: 12.5 }}>{w.title}</span>
            <div style={{ width: 56 }}>
              <div style={{ height: 3, background: 'var(--border)', borderRadius: 2 }}>
                <div style={{ width: `${pct * 100}%`, height: '100%', background: z.color, borderRadius: 2 }} />
              </div>
              <div className="mono dim" style={{ fontSize: 10, marginTop: 2 }}>{w.steps_done}/{w.steps_total}</div>
            </div>
          </div>
        );
      })}
    </div>
  );
}

function WWheel({ state }) {
  const overall = ZONES.reduce((s, z) => s + state.wheel.current[z.id], 0) / 8;
  const weak = ZONES
    .map(z => ({ z, d: state.wheel.target[z.id] - state.wheel.current[z.id] }))
    .filter(({ d }) => d > 0).sort((a, b) => b.d - a.d).slice(0, 3);
  return (
    <div className="row" style={{ flex: 1, gap: 14, alignItems: 'center' }}>
      <ProgressRing value={overall / 10} size={80} stroke={7} color="var(--accent)" label={overall.toFixed(1)} sub="из 10" />
      <div style={{ flex: 1, minWidth: 0 }}>
        <div className="eyebrow mb-2">Слабые зоны</div>
        <div className="col" style={{ gap: 4, fontSize: 12 }}>
          {weak.map(({ z, d }) => (
            <div key={z.id} className="row" style={{ justifyContent: 'space-between' }}>
              <span><span style={{ color: z.color }}>{z.icon}</span> {z.name}</span>
              <span className="mono dim">−{d}</span>
            </div>
          ))}
        </div>
      </div>
    </div>
  );
}

function WLeader() {
  return (
    <div className="col" style={{ gap: 6, flex: 1 }}>
      {LEADER.map((row, i) => {
        const u = USER_BY_ID[row.user];
        const max = LEADER[0].xp;
        return (
          <div key={u.id} className="row" style={{ gap: 8, alignItems: 'center' }}>
            <div className="mono" style={{ width: 14, fontWeight: 700, color: i === 0 ? 'var(--gold)' : 'var(--text-tertiary)', fontSize: 11 }}>{i + 1}</div>
            <Avatar user={u} size="sm" />
            <div style={{ flex: 1, minWidth: 0 }}>
              <div className="spread" style={{ fontSize: 11.5, marginBottom: 2 }}>
                <span style={{ fontWeight: u.id === ME.id ? 700 : 500 }}>{u.name}{u.id === ME.id && ' (вы)'}</span>
                <span className="mono dim" style={{ fontSize: 10 }}>{row.xp} XP</span>
              </div>
              <div style={{ height: 3, background: 'var(--border)', borderRadius: 2 }}>
                <div style={{ width: `${(row.xp / max) * 100}%`, height: '100%', background: u.color, borderRadius: 2, transition: 'width 600ms cubic-bezier(0.22, 1, 0.36, 1)' }} />
              </div>
            </div>
          </div>
        );
      })}
    </div>
  );
}

function WFeed() {
  return (
    <div className="col" style={{ gap: 0, flex: 1, overflowY: 'auto', maxHeight: 240 }}>
      {FEED.slice(0, 4).map(f => {
        const u = USER_BY_ID[f.who];
        return (
          <div key={f.id} className="feed-item" style={{ padding: '8px 0' }}>
            <Avatar user={u} size="sm" />
            <div className="body">
              <div style={{ fontSize: 12, lineHeight: 1.4 }}>
                <strong>{u.name}</strong>{' '}
                <span dangerouslySetInnerHTML={{ __html: f.text }} />
              </div>
              <div className="when" style={{ fontSize: 10, marginTop: 2 }}>{f.when} назад</div>
            </div>
          </div>
        );
      })}
    </div>
  );
}

function WBadges() {
  const pinned = BADGES.filter(b => b.pinned).concat(BADGES.filter(b => b.earned && !b.pinned)).slice(0, 6);
  return (
    <div style={{ display: 'grid', gridTemplateColumns: 'repeat(3, 1fr)', gap: 6, flex: 1 }}>
      {pinned.map(b => <BadgeCell key={b.id} badge={b} />)}
    </div>
  );
}

const WIDGET_RENDERERS = {
  mascot: WMascot, xp: WXP, streak: WStreak, zones: WZones,
  today: WToday, focus: WFocus, wheel: WWheel, leader: WLeader,
  feed: WFeed, badges: WBadges,
};

// ── Widget shell ──────────────────────────────────────────────
function Widget({ widget, state, dispatch, dragging, dragTarget, onDragStart, onDragOver, onDrop, onResize, onHide, editMode }) {
  const meta = WIDGET_META[widget.id];
  const Body = WIDGET_RENDERERS[widget.id];
  if (!Body || !meta) return null;
  return (
    <div className={`widget ${dragging ? 'dragging' : ''} ${dragTarget ? 'drag-target' : ''}`}
         data-size={widget.size}
         draggable
         onDragStart={onDragStart}
         onDragOver={onDragOver}
         onDragEnter={onDragOver}
         onDrop={onDrop}>
      <div className="widget-chrome">
        {['s','m','l'].map(s => (
          <button key={s} className={widget.size === s ? 'active' : ''}
                  title={`размер ${s.toUpperCase()}`}
                  onClick={() => onResize(s)}>{s.toUpperCase()}</button>
        ))}
        <button title="скрыть" onClick={onHide}>×</button>
      </div>
      <div className="widget-head widget-handle">
        <span className="ico">{meta.icon}</span>
        <span>{meta.title}</span>
      </div>
      <Body state={state} dispatch={dispatch} />
    </div>
  );
}

// ── Dashboard with widget grid ────────────────────────────────
function CustomizableDashboard({ state, dispatch, layout, onLayoutChange }) {
  const [editMode, setEditMode] = React.useState(false);
  const [adding, setAdding] = React.useState(false);
  const [dragId, setDragId] = React.useState(null);
  const [overId, setOverId] = React.useState(null);

  const visible = layout.filter(w => w.visible);
  const hidden = layout.filter(w => !w.visible);

  const onDragStart = (id) => (e) => {
    e.dataTransfer.effectAllowed = 'move';
    setDragId(id);
  };
  const onDragOver = (id) => (e) => {
    e.preventDefault();
    setOverId(id);
  };
  const onDrop = (targetId) => (e) => {
    e.preventDefault();
    if (!dragId || dragId === targetId) { setDragId(null); setOverId(null); return; }
    const next = [...layout];
    const fromIdx = next.findIndex(w => w.id === dragId);
    const toIdx = next.findIndex(w => w.id === targetId);
    if (fromIdx < 0 || toIdx < 0) return;
    const [moved] = next.splice(fromIdx, 1);
    next.splice(toIdx, 0, moved);
    onLayoutChange(next);
    setDragId(null); setOverId(null);
  };
  const resize = (id, size) => {
    onLayoutChange(layout.map(w => w.id === id ? { ...w, size } : w));
  };
  const hide = (id) => {
    onLayoutChange(layout.map(w => w.id === id ? { ...w, visible: false } : w));
  };
  const show = (id) => {
    onLayoutChange(layout.map(w => w.id === id ? { ...w, visible: true } : w));
    setAdding(false);
  };
  const reset = () => {
    onLayoutChange(DEFAULT_LAYOUT.map(w => ({ ...w })));
  };

  return (
    <div className={editMode ? 'widget-edit' : ''}>
      {/* Toolbar */}
      <div className="dash-toolbar">
        <span className="pill">{editMode ? 'Режим редактирования' : 'Дашборд'}</span>
        <span className="dim" style={{ fontSize: 12 }}>
          {editMode
            ? 'Перетаскивай карточки, меняй размер (S/M/L), скрывай или добавляй'
            : `${visible.length} виджет${visible.length === 1 ? '' : visible.length < 5 ? 'а' : 'ов'} · Канвас можно перестроить`}
        </span>
        <div style={{ flex: 1 }}></div>
        {hidden.length > 0 && (
          <button className="btn ghost" style={{ fontSize: 12, padding: '5px 10px' }} onClick={() => setAdding(true)}>
            <Icon.plus style={{ width: 12, height: 12 }} /> Виджет ({hidden.length})
          </button>
        )}
        <button className="btn ghost" style={{ fontSize: 12, padding: '5px 10px' }} onClick={reset}>
          Сбросить
        </button>
        <button className={`btn ${editMode ? 'primary' : ''}`}
                style={{ fontSize: 12, padding: '5px 10px' }}
                onClick={() => setEditMode(!editMode)}>
          {editMode ? '✓ Готово' : '✎ Настроить'}
        </button>
      </div>

      {/* Grid */}
      <div className="dash-grid">
        {visible.map(w => (
          <Widget
            key={w.id}
            widget={w}
            state={state}
            dispatch={dispatch}
            dragging={dragId === w.id}
            dragTarget={overId === w.id && dragId !== w.id}
            onDragStart={onDragStart(w.id)}
            onDragOver={onDragOver(w.id)}
            onDrop={onDrop(w.id)}
            onResize={(s) => resize(w.id, s)}
            onHide={() => hide(w.id)}
            editMode={editMode}
          />
        ))}
        {editMode && hidden.length > 0 && (
          <div className="widget-add" style={{ gridColumn: 'span 4' }} onClick={() => setAdding(true)}>
            <span style={{ fontSize: 22 }}>+</span>
            <span>Добавить виджет</span>
          </div>
        )}
      </div>

      {/* Add panel */}
      {adding && (
        <div className="add-overlay" onClick={() => setAdding(false)}>
          <div className="panel" onClick={(e) => e.stopPropagation()}>
            <div className="ttl-md mb-3">Скрытые виджеты</div>
            {hidden.length === 0 ? (
              <div className="dim" style={{ fontSize: 13 }}>Все виджеты уже на дашборде. Можно скрыть лишние через ×.</div>
            ) : (
              <div className="col" style={{ gap: 6 }}>
                {hidden.map(w => {
                  const m = WIDGET_META[w.id];
                  return (
                    <div key={w.id} className="row"
                         onClick={() => show(w.id)}
                         style={{
                           padding: '10px 12px', borderRadius: 'var(--r-md)',
                           border: '1px solid var(--border)', background: 'var(--bg-elev)',
                           cursor: 'pointer', gap: 10,
                         }}>
                      <span style={{ fontSize: 18 }}>{m.icon}</span>
                      <span style={{ flex: 1, fontWeight: 500 }}>{m.title}</span>
                      <span className="mono dim" style={{ fontSize: 11 }}>Добавить →</span>
                    </div>
                  );
                })}
              </div>
            )}
            <div className="row mt-4" style={{ justifyContent: 'flex-end' }}>
              <button className="btn" onClick={() => setAdding(false)}>Закрыть</button>
            </div>
          </div>
        </div>
      )}
    </div>
  );
}

Object.assign(window, {
  DEFAULT_LAYOUT, WIDGET_META, WIDGET_RENDERERS, Widget, CustomizableDashboard,
});
