// DSDataViz.jsx — Meridian data-viz primitives
//
//   DSProgressBar     — linear progress with axis/warn/crisis tones
//   DSBarMeter        — categorical bars (e.g. weekly activity)
//   DSBigStat         — very large number + label, for empty-state heroes
//   DSCorrelationList — list of correlated parameters with strength + direction
//   DSSkeletonLoader  — shimmer placeholder for content
//
// All five are SVG/DOM only — no canvas, no chart library.

// ── Shared tone palette ──────────────────────────────────────────
const DS_TONES = {
  axis:    { fg: M.axis,    bg: M.rule,        soft: M.axisSoft },
  success: { fg: M.success, bg: '#D7E8DC',     soft: '#EBF3EE' },
  warning: { fg: M.warning, bg: '#F2DFA4',     soft: '#FFFBEB' },
  crisis:  { fg: M.crisis,  bg: '#F2C9C9',     soft: '#FFF2F2' },
  neutral: { fg: M.inkMuted,bg: M.rule,        soft: M.ruleSoft },
};

// ── DSProgressBar ────────────────────────────────────────────────
function DSProgressBar({
  progress,            // 0..1
  tone = 'axis',
  label,
  countLabel,
  height = 6,
  style,
}) {
  const t = DS_TONES[tone] || DS_TONES.axis;
  const p = Math.max(0, Math.min(1, progress));
  return (
    <div style={{ ...style }}>
      {(label || countLabel) && (
        <div style={{ display: 'flex', alignItems: 'baseline', justifyContent: 'space-between', marginBottom: 6 }}>
          {label && <div style={{ font: `400 11px/1 ${M.mono}`, color: M.inkMuted, fontVariantNumeric: 'tabular-nums' }}>{label}</div>}
          {countLabel && <div style={{ font: `400 11px/1 ${M.mono}`, color: M.inkMuted, fontVariantNumeric: 'tabular-nums' }}>{countLabel}</div>}
        </div>
      )}
      <div role="progressbar" aria-valuenow={p * 100} aria-valuemin={0} aria-valuemax={100} style={{
        position: 'relative', width: '100%', height,
        background: t.bg, borderRadius: 999, overflow: 'hidden',
      }}>
        <div style={{
          position: 'absolute', left: 0, top: 0, bottom: 0,
          width: `${p * 100}%`,
          background: t.fg,
          borderRadius: 999,
          transition: 'width 220ms cubic-bezier(.2,.8,.2,1)',
        }} />
      </div>
    </div>
  );
}

// ── DSBarMeter ───────────────────────────────────────────────────
// Categorical bars. `bars: [{ heightRatio: 0..1, isHighlighted?, label? }]`
// Optional bottom-axis labels.
function DSBarMeter({
  bars,
  totalHeight = 56,
  gap = 2,
  color = M.axis,
  showLabels = true,
  style,
}) {
  const t = DS_TONES.axis;
  return (
    <div style={{ ...style }}>
      <div style={{ display: 'flex', alignItems: 'flex-end', gap, height: totalHeight }}>
        {bars.map((b, i) => {
          const h = Math.max(2, b.heightRatio * totalHeight); // floor 2px so empty bars are visible
          return (
            <div key={i} style={{
              flex: 1,
              height: h,
              background: b.isHighlighted ? color : t.soft,
              borderRadius: 2,
              transition: 'height 220ms cubic-bezier(.2,.8,.2,1), background 120ms cubic-bezier(.2,.8,.2,1)',
            }} aria-hidden="true" />
          );
        })}
      </div>
      {showLabels && bars.some(b => b.label) && (
        <div style={{ display: 'flex', gap, marginTop: 6 }}>
          {bars.map((b, i) => (
            <div key={i} style={{
              flex: 1, textAlign: 'center',
              font: `400 10px/1 ${M.mono}`,
              color: b.isHighlighted ? M.ink : M.inkFaint,
              fontVariantNumeric: 'tabular-nums',
            }}>{b.label || ''}</div>
          ))}
        </div>
      )}
    </div>
  );
}

// ── DSBigStat ────────────────────────────────────────────────────
// Empty-state hero number. Designed to land in the middle of an empty
// surface so the user sees the count, not the absence of data.
function DSBigStat({
  value,
  label,
  sub,
  tone = 'neutral',
  size = 'lg',
  style,
}) {
  const t = DS_TONES[tone] || DS_TONES.neutral;
  const sizes = {
    md: { num: 44, sub: 13 },
    lg: { num: 64, sub: 14 },
    xl: { num: 84, sub: 15 },
  };
  const s = sizes[size] || sizes.lg;
  return (
    <div style={{ textAlign: 'center', ...style }}>
      <div style={{
        font: `500 ${s.num}px/1 ${M.sans}`,
        color: tone === 'neutral' ? M.ink : t.fg,
        letterSpacing: '-0.025em',
        fontVariantNumeric: 'tabular-nums',
      }}>{value}</div>
      {label && (
        <div style={{
          font: `500 11px/1 ${M.sans}`, color: M.inkMuted,
          letterSpacing: '0.08em', textTransform: 'uppercase',
          marginTop: 10,
        }}>{label}</div>
      )}
      {sub && (
        <div style={{
          font: `400 ${s.sub}px/1.5 ${M.sans}`, color: M.inkSoft,
          marginTop: 8, maxWidth: 320, marginLeft: 'auto', marginRight: 'auto',
        }}>{sub}</div>
      )}
    </div>
  );
}

// ── DSCorrelationList ────────────────────────────────────────────
// `items: [{ factor, strength, direction, overlap?, onTap? }]`
//   strength  — 'strong' | 'moderate' | 'weak'
//   direction — 'up' (helping) | 'down' (hurting) | 'neutral'
//   overlap   — string like "4 of 7 nights"
const STRENGTH_LABELS = {
  strong:   'Strong',
  moderate: 'Moderate',
  weak:     'Weak',
};
function DSCorrelationList({
  title,
  items = [],
  emptyHint = 'Not enough overlapping data yet — try logging both for two weeks.',
  style,
}) {
  return (
    <div style={style}>
      {title && (
        <div style={{
          font: `500 11px/1 ${M.sans}`, color: M.inkMuted,
          letterSpacing: '0.06em', textTransform: 'uppercase',
          marginBottom: 10,
        }}>{title}</div>
      )}
      {items.length === 0 ? (
        <div style={{
          font: `400 13px/1.5 ${M.sans}`, color: M.inkMuted, textAlign: 'center',
          padding: '14px 12px',
          border: `1px dashed ${M.rule}`, borderRadius: 12,
        }}>{emptyHint}</div>
      ) : (
        <div style={{
          background: M.surface, border: `1px solid ${M.rule}`, borderRadius: 16,
          overflow: 'hidden',
        }}>
          {items.map((it, i) => (
            <DSCorrelationRow key={i} {...it} isLast={i === items.length - 1} />
          ))}
        </div>
      )}
    </div>
  );
}

function DSCorrelationRow({ factor, strength = 'moderate', direction = 'neutral', overlap, onTap, isLast }) {
  const isUp = direction === 'up';
  const isDown = direction === 'down';
  const indicatorBg = isUp ? '#EBF3EE' : (isDown ? '#FFF2F2' : M.surfaceAlt);
  const indicatorFg = isUp ? M.success : (isDown ? M.crisis : M.inkMuted);
  return (
    <div
      onClick={onTap}
      role={onTap ? 'button' : undefined}
      tabIndex={onTap ? 0 : undefined}
      onKeyDown={onTap ? (e) => { if (e.key === 'Enter' || e.key === ' ') { e.preventDefault(); onTap(); } } : undefined}
      style={{
        display: 'flex', alignItems: 'center', gap: 12,
        padding: '12px 14px',
        borderBottom: isLast ? 'none' : `1px solid ${M.ruleSoft}`,
        cursor: onTap ? 'pointer' : 'default',
        outline: 'none',
      }}>
      <div aria-hidden="true" style={{
        width: 32, height: 32, borderRadius: 8,
        background: indicatorBg, color: indicatorFg,
        display: 'flex', alignItems: 'center', justifyContent: 'center', flexShrink: 0,
      }}>
        <svg width="16" height="16" viewBox="0 0 24 24" fill="none">
          {isUp && <path d="M12 19V5M6 11l6-6 6 6" stroke="currentColor" strokeWidth="2.2" strokeLinecap="round" strokeLinejoin="round"/>}
          {isDown && <path d="M12 5v14M6 13l6 6 6-6" stroke="currentColor" strokeWidth="2.2" strokeLinecap="round" strokeLinejoin="round"/>}
          {!isUp && !isDown && <line x1="6" y1="12" x2="18" y2="12" stroke="currentColor" strokeWidth="2.2" strokeLinecap="round"/>}
        </svg>
      </div>
      <div style={{ flex: 1, minWidth: 0 }}>
        <div style={{
          font: `400 14px/1.3 ${M.sans}`, color: M.ink,
          overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap',
        }}>{factor}</div>
        <div style={{
          font: `400 11px/1.3 ${M.mono}`, color: M.inkMuted,
          marginTop: 2, fontVariantNumeric: 'tabular-nums',
        }}>
          {STRENGTH_LABELS[strength] || strength}
          {overlap ? <span> · {overlap}</span> : null}
        </div>
      </div>
      {onTap && (
        <svg width="14" height="14" viewBox="0 0 24 24" fill="none" aria-hidden="true">
          <path d="M9 6l6 6-6 6" stroke={M.inkFaint} strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"/>
        </svg>
      )}
    </div>
  );
}

// ── DSSkeletonLoader ─────────────────────────────────────────────
// Shimmer placeholder. Pass `lineCount` for a stacked text block, or use
// `lines: [{ height, width }]` for custom shapes (e.g. a tile loader).
function DSSkeletonLoader({
  lineCount = 3,
  lines,        // optional [{ height, width, gap? }]
  style,
  rounded = 6,
}) {
  const lineSpec = lines || Array.from({ length: lineCount }, (_, i) => ({
    height: 14,
    width: i === lineCount - 1 ? '60%' : '100%',
  }));
  return (
    <div style={{
      display: 'flex', flexDirection: 'column', gap: 10,
      width: '100%',
      ...style,
    }} aria-busy="true" aria-live="polite">
      <style>{`
        @keyframes meridian-shimmer {
          0%   { background-position: 200% 0; }
          100% { background-position: -200% 0; }
        }
      `}</style>
      {lineSpec.map((l, i) => (
        <div key={i} style={{
          height: l.height,
          width: l.width,
          borderRadius: rounded,
          background: `linear-gradient(90deg, ${M.ruleSoft} 0%, ${M.canvas} 40%, ${M.ruleSoft} 80%)`,
          backgroundSize: '200% 100%',
          animation: 'meridian-shimmer 1.4s linear infinite',
        }} />
      ))}
    </div>
  );
}

Object.assign(window, {
  DSProgressBar, DSBarMeter, DSBigStat, DSCorrelationList, DSCorrelationRow, DSSkeletonLoader,
  DS_TONES,
});
