/* global React, Icon, useSelectedWorkspaceId */
/*
 * Analytics page.
 *
 * Everything rendered here comes from /api/analytics/*. There are no sample
 * values, no placeholder series and no client-side metric maths: labels, units,
 * comparison values and completeness flags all arrive from the server's shared
 * metric definitions, so the page cannot drift from the definitions the API
 * enforces.
 */
const {
  useCallback: useCallbackAnalytics,
  useEffect: useEffectAnalytics,
  useMemo: useMemoAnalytics,
  useRef: useRefAnalytics,
  useState: useStateAnalytics,
} = React;

const ANALYTICS_CHANNEL_LABELS = {
  website: 'Website',
  whatsapp: 'WhatsApp',
  messenger: 'Messenger',
  instagram: 'Instagram',
};

const ANALYTICS_EXPORTS = [
  { value: 'summary', label: 'Summary metrics' },
  { value: 'timeseries', label: 'Daily time series' },
  { value: 'bots', label: 'Bot performance' },
  { value: 'channels', label: 'Channel performance' },
  { value: 'leads', label: 'Leads summary' },
  { value: 'agents', label: 'Agent performance' },
  { value: 'ai-usage', label: 'AI usage' },
  { value: 'all', label: 'Everything' },
];

/* ------------------------------------------------------------------ *
 * Formatting
 * ------------------------------------------------------------------ */

function formatMetricValue(metric) {
  if (!metric) return '—';
  const value = Number(metric.value || 0);

  if (metric.unit === 'rate') {
    if (metric.hasDenominator === false) return '—';
    return `${(value * 100).toFixed(value < 0.1 ? 1 : 0)}%`;
  }
  if (metric.unit === 'duration_ms') {
    if (metric.hasDenominator === false) return '—';
    return formatDuration(value);
  }
  if (metric.unit === 'currency_usd') {
    return value >= 1 ? `$${value.toFixed(2)}` : `$${value.toFixed(4)}`;
  }
  return formatCount(value);
}

function formatCount(value) {
  const number = Number(value || 0);
  if (!Number.isFinite(number)) return '0';
  if (Math.abs(number) >= 1000000) return `${(number / 1000000).toFixed(1)}M`;
  if (Math.abs(number) >= 10000) return `${(number / 1000).toFixed(1)}k`;
  return number.toLocaleString();
}

function formatDuration(ms) {
  const value = Number(ms || 0);
  if (!Number.isFinite(value) || value <= 0) return '—';
  if (value < 1000) return `${Math.round(value)}ms`;
  if (value < 60000) return `${(value / 1000).toFixed(1)}s`;
  if (value < 3600000) return `${Math.round(value / 60000)}m`;
  const hours = Math.floor(value / 3600000);
  const minutes = Math.round((value % 3600000) / 60000);
  return minutes ? `${hours}h ${minutes}m` : `${hours}h`;
}

function formatRate(rate) {
  if (!rate || rate.hasDenominator === false) return '—';
  return `${(Number(rate.value || 0) * 100).toFixed(0)}%`;
}

function formatDateLabel(value) {
  const parts = String(value || '').split('-');
  if (parts.length !== 3) return String(value || '');
  const date = new Date(Date.UTC(Number(parts[0]), Number(parts[1]) - 1, Number(parts[2])));
  return date.toLocaleDateString(undefined, { day: 'numeric', month: 'short', timeZone: 'UTC' });
}

function channelLabel(channelType) {
  return ANALYTICS_CHANNEL_LABELS[channelType] || channelType || 'Unknown';
}

/* ------------------------------------------------------------------ *
 * Trend indicator — colour is never the only signal
 * ------------------------------------------------------------------ */

function TrendDelta({ metric }) {
  if (!metric) return null;

  const change = metric.percentageChange;
  const goodDirection = metric.goodDirection || 'up';

  if (change === null || change === undefined) {
    const hadPrevious = Number(metric.previousValue || 0) !== 0;
    return (
      <span className="analytics-delta is-flat">
        <span className="analytics-delta-glyph" aria-hidden="true">—</span>
        <span className="analytics-delta-note">
          {hadPrevious ? 'no comparison' : 'no prior data'}
        </span>
      </span>
    );
  }

  const rounded = Math.round(Math.abs(change));
  if (rounded === 0) {
    return (
      <span className="analytics-delta is-flat">
        <span className="analytics-delta-glyph" aria-hidden="true">—</span>
        <span>No change</span>
      </span>
    );
  }

  const rising = change > 0;
  const isGood = goodDirection === 'up' ? rising : !rising;
  const directionWord = rising ? 'up' : 'down';

  return (
    <span className={`analytics-delta ${isGood ? 'is-good' : 'is-bad'}`}>
      <span className="analytics-delta-glyph" aria-hidden="true">{rising ? '▲' : '▼'}</span>
      <span>
        {directionWord} {rounded}%
      </span>
      <span className="analytics-sr-only">
        compared with the previous period, which is {isGood ? 'better' : 'worse'}
      </span>
    </span>
  );
}

/* ------------------------------------------------------------------ *
 * KPI row
 * ------------------------------------------------------------------ */

function KpiCard({ metric, definition }) {
  if (!metric) return null;

  const isPartial = metric.completeness === 'partial';
  const describedBy = `kpi-desc-${metric.key}`;

  return (
    <div className="analytics-kpi">
      <div className="analytics-kpi-label">
        <span>{metric.label}</span>
        {definition && (
          <span
            title={`${definition.numerator}\n\nDenominator: ${definition.denominator}\nDate filter: ${definition.timestamp}`}
            aria-hidden="true"
          >
            <Icon name="info" size={12} />
          </span>
        )}
      </div>
      <div className={`analytics-kpi-value ${metric.hasDenominator === false ? 'is-empty' : ''}`}>
        {formatMetricValue(metric)}
      </div>
      <TrendDelta metric={metric} />
      {isPartial && <span className="analytics-partial">Partial history</span>}
      <span id={describedBy} className="analytics-sr-only">
        {definition ? definition.numerator : metric.label}
      </span>
    </div>
  );
}

/* ------------------------------------------------------------------ *
 * Trend chart — accessible inline SVG
 * ------------------------------------------------------------------ */

function TrendChart({ points, metricKey, definitions, metricKeys, onMetricChange }) {
  const [hoverIndex, setHoverIndex] = useStateAnalytics(-1);
  const wrapRef = useRefAnalytics(null);

  const definition = definitions?.[metricKey] || null;
  const previousKey = `previous${metricKey.charAt(0).toUpperCase()}${metricKey.slice(1)}`;

  const series = useMemoAnalytics(
    () =>
      (points || []).map((point) => ({
        date: point.date,
        current: Number(point[metricKey] || 0),
        previous: Number(point[previousKey] || 0),
      })),
    [points, metricKey, previousKey],
  );

  const hasData = series.some((item) => item.current > 0 || item.previous > 0);
  const width = 720;
  const height = 240;
  const padding = { top: 16, right: 12, bottom: 26, left: 44 };
  const innerWidth = width - padding.left - padding.right;
  const innerHeight = height - padding.top - padding.bottom;

  const maxValue = Math.max(1, ...series.map((item) => Math.max(item.current, item.previous)));
  const stepX = series.length > 1 ? innerWidth / (series.length - 1) : 0;

  const pointX = (index) => padding.left + (series.length > 1 ? index * stepX : innerWidth / 2);
  const pointY = (value) => padding.top + innerHeight - (value / maxValue) * innerHeight;

  const toPath = (key) =>
    series.map((item, index) => `${index === 0 ? 'M' : 'L'}${pointX(index)},${pointY(item[key])}`).join(' ');

  const areaPath = series.length
    ? `${toPath('current')} L${pointX(series.length - 1)},${padding.top + innerHeight} L${pointX(0)},${padding.top + innerHeight} Z`
    : '';

  const isCost = definition?.unit === 'currency_usd';
  const formatValue = (value) =>
    isCost ? `$${Number(value).toFixed(2)}` : formatCount(value);

  // Label density adapts to range length so a 90-day chart stays readable.
  const labelEvery = Math.max(1, Math.ceil(series.length / 8));
  const hovered = hoverIndex >= 0 ? series[hoverIndex] : null;

  const handlePointer = (event) => {
    if (!series.length) return;
    const svg = event.currentTarget;
    const rect = svg.getBoundingClientRect();
    const relativeX = ((event.clientX - rect.left) / rect.width) * width;
    const index = series.length > 1
      ? Math.round((relativeX - padding.left) / stepX)
      : 0;
    setHoverIndex(Math.min(series.length - 1, Math.max(0, index)));
  };

  const handleKeyDown = (event) => {
    if (!series.length) return;
    if (event.key === 'ArrowRight') {
      event.preventDefault();
      setHoverIndex((index) => Math.min(series.length - 1, (index < 0 ? -1 : index) + 1));
    } else if (event.key === 'ArrowLeft') {
      event.preventDefault();
      setHoverIndex((index) => Math.max(0, (index < 0 ? series.length : index) - 1));
    } else if (event.key === 'Escape') {
      setHoverIndex(-1);
    }
  };

  const total = series.reduce((sum, item) => sum + item.current, 0);
  const previousTotal = series.reduce((sum, item) => sum + item.previous, 0);
  const chartDescription = `${definition?.label || metricKey} by day. ${formatValue(total)} in the selected period against ${formatValue(previousTotal)} in the previous period.`;

  return (
    <section className="analytics-card" aria-labelledby="analytics-trend-title">
      <div className="analytics-card-head">
        <div>
          <div className="analytics-card-title" id="analytics-trend-title">
            Trend
          </div>
          <div className="analytics-card-sub">{definition?.numerator || ''}</div>
        </div>
        <div className="analytics-field">
          <label htmlFor="analytics-trend-metric">Metric</label>
          <select
            id="analytics-trend-metric"
            className="analytics-select"
            value={metricKey}
            onChange={(event) => onMetricChange(event.target.value)}
          >
            {(metricKeys || []).map((key) => (
              <option key={key} value={key}>
                {definitions?.[key]?.label || key}
              </option>
            ))}
          </select>
        </div>
      </div>

      {!hasData ? (
        <div className="analytics-empty">
          <strong>No {(definition?.label || metricKey).toLowerCase()} in this period</strong>
          Try a longer date range, or clear the bot and channel filters.
        </div>
      ) : (
        <div className="analytics-chart-wrap" ref={wrapRef}>
          <svg
            className="analytics-chart"
            viewBox={`0 0 ${width} ${height}`}
            role="img"
            tabIndex={0}
            aria-label={chartDescription}
            onMouseMove={handlePointer}
            onMouseLeave={() => setHoverIndex(-1)}
            onKeyDown={handleKeyDown}
            onBlur={() => setHoverIndex(-1)}
          >
            <desc>{chartDescription}</desc>

            {[0, 0.25, 0.5, 0.75, 1].map((ratio) => {
              const y = padding.top + innerHeight * ratio;
              return (
                <g key={ratio}>
                  <line
                    className="analytics-chart-grid"
                    x1={padding.left}
                    x2={width - padding.right}
                    y1={y}
                    y2={y}
                  />
                  <text className="analytics-chart-axis" x={padding.left - 8} y={y + 3} textAnchor="end">
                    {formatValue(maxValue * (1 - ratio))}
                  </text>
                </g>
              );
            })}

            <path className="analytics-chart-area" d={areaPath} />
            <path className="analytics-chart-previous" d={toPath('previous')} />
            <path className="analytics-chart-current" d={toPath('current')} />

            {series.map((item, index) =>
              index % labelEvery === 0 || index === series.length - 1 ? (
                <text
                  key={item.date}
                  className="analytics-chart-axis"
                  x={pointX(index)}
                  y={height - 8}
                  textAnchor="middle"
                >
                  {formatDateLabel(item.date)}
                </text>
              ) : null,
            )}

            {hovered && (
              <g>
                <line
                  className="analytics-chart-cursor"
                  x1={pointX(hoverIndex)}
                  x2={pointX(hoverIndex)}
                  y1={padding.top}
                  y2={padding.top + innerHeight}
                />
                <circle className="analytics-chart-marker" cx={pointX(hoverIndex)} cy={pointY(hovered.current)} r={4} />
              </g>
            )}
          </svg>

          {hovered && (
            <div
              className="analytics-tooltip"
              role="status"
              style={{
                left: `${(pointX(hoverIndex) / width) * 100}%`,
                top: 0,
                transform: 'translate(-50%, -110%)',
              }}
            >
              <div>{formatDateLabel(hovered.date)}</div>
              <div>
                This period: <strong>{formatValue(hovered.current)}</strong>
              </div>
              <div>
                Previous: <strong>{formatValue(hovered.previous)}</strong>
              </div>
            </div>
          )}

          <div className="analytics-legend">
            <span className="analytics-legend-item">
              <span className="analytics-legend-swatch" aria-hidden="true" />
              Selected period
            </span>
            <span className="analytics-legend-item">
              <span className="analytics-legend-swatch is-previous" aria-hidden="true" />
              Previous period (dashed)
            </span>
          </div>
        </div>
      )}
    </section>
  );
}

/* ------------------------------------------------------------------ *
 * Funnel
 * ------------------------------------------------------------------ */

function FunnelPanel({ steps }) {
  const available = (steps || []).filter((step) => step.available);
  const max = Math.max(1, ...available.map((step) => step.value));

  return (
    <section className="analytics-card" aria-labelledby="analytics-funnel-title">
      <div className="analytics-card-head">
        <div>
          <div className="analytics-card-title" id="analytics-funnel-title">
            Conversion funnel
          </div>
          <div className="analytics-card-sub">Impression through to outcome</div>
        </div>
      </div>

      <div className="analytics-funnel">
        {(steps || []).map((step) => {
          const width = step.available ? Math.max(2, (step.value / max) * 100) : 100;
          return (
            <div
              key={step.key}
              className={`analytics-funnel-step ${step.available ? '' : 'is-unavailable'}`}
            >
              <span className="analytics-funnel-label">{step.label}</span>
              <span className="analytics-funnel-value">
                {step.available ? formatCount(step.value) : 'Not available'}
              </span>
              <div
                className="analytics-funnel-bar"
                role="img"
                aria-label={
                  step.available
                    ? `${step.label}: ${step.value}`
                    : `${step.label}: not recorded for this period`
                }
              >
                <div className="analytics-funnel-fill" style={{ width: `${width}%` }} />
              </div>
              {step.note && <p className="analytics-funnel-note">{step.note}</p>}
            </div>
          );
        })}
      </div>
    </section>
  );
}

/* ------------------------------------------------------------------ *
 * Generic table panel
 * ------------------------------------------------------------------ */

function TablePanel({ title, subtitle, columns, rows, emptyMessage, caption }) {
  return (
    <section className="analytics-card">
      <div className="analytics-card-head">
        <div>
          <div className="analytics-card-title">{title}</div>
          {subtitle && <div className="analytics-card-sub">{subtitle}</div>}
        </div>
      </div>

      {!rows || !rows.length ? (
        <div className="analytics-empty">{emptyMessage || 'Nothing recorded in this period.'}</div>
      ) : (
        <div className="analytics-table-scroll">
          <table className="analytics-table">
            {caption && <caption>{caption}</caption>}
            <thead>
              <tr>
                {columns.map((column) => (
                  <th key={column.key} className={column.numeric ? 'is-num' : ''} scope="col">
                    {column.label}
                  </th>
                ))}
              </tr>
            </thead>
            <tbody>
              {rows.map((row, index) => (
                <tr key={row.id || index}>
                  {columns.map((column) => (
                    <td key={column.key} className={column.numeric ? 'is-num' : ''}>
                      {column.render(row)}
                    </td>
                  ))}
                </tr>
              ))}
            </tbody>
          </table>
        </div>
      )}
    </section>
  );
}

/* ------------------------------------------------------------------ *
 * Drill-down drawer
 * ------------------------------------------------------------------ */

function DrilldownDrawer({ state, onClose }) {
  const closeRef = useRefAnalytics(null);

  useEffectAnalytics(() => {
    if (!state) return undefined;
    const onKeyDown = (event) => {
      if (event.key === 'Escape') onClose();
    };
    window.addEventListener('keydown', onKeyDown);
    if (closeRef.current) closeRef.current.focus();
    return () => window.removeEventListener('keydown', onKeyDown);
  }, [state, onClose]);

  if (!state) return null;

  const openConversation = (conversationId) => {
    try {
      window.sessionStorage.setItem('pluginchatbot_open_conversation', conversationId);
    } catch (error) {
      // Session storage may be unavailable; the inbox still opens.
    }
    window.location.assign('/conversations');
  };

  return (
    <div
      className="analytics-drawer-backdrop"
      role="presentation"
      onClick={(event) => {
        if (event.target === event.currentTarget) onClose();
      }}
    >
      <aside
        className="analytics-drawer"
        role="dialog"
        aria-modal="true"
        aria-labelledby="analytics-drawer-title"
      >
        <div className="analytics-drawer-head">
          <div style={{ flex: 1, minWidth: 0 }}>
            <h2 id="analytics-drawer-title">{state.title}</h2>
            <div className="analytics-card-sub">{state.subtitle}</div>
          </div>
          <button
            type="button"
            className="btn btn-secondary"
            onClick={onClose}
            ref={closeRef}
            aria-label="Close details"
          >
            <Icon name="x" size={14} />
          </button>
        </div>

        <div className="analytics-drawer-body">
          {state.loading && <div className="analytics-empty">Loading matching conversations…</div>}

          {!state.loading && state.error && (
            <div className="analytics-notice is-error">
              <Icon name="alertTriangle" size={15} />
              <span>{state.error}</span>
            </div>
          )}

          {!state.loading && !state.error && !state.conversations.length && (
            <div className="analytics-empty">
              <strong>No matching conversations</strong>
              These may have been deleted, or fall outside the selected date range.
            </div>
          )}

          {!state.loading &&
            state.conversations.map((item) => (
              <div className="analytics-drawer-item" key={`${item.botId}:${item.sessionKey}`}>
                <div style={{ display: 'flex', gap: 8, alignItems: 'center', flexWrap: 'wrap' }}>
                  <span className="analytics-status">{channelLabel(item.channelType)}</span>
                  <span className="analytics-status">{item.botName}</span>
                  {item.aiContained ? (
                    <span className="analytics-status is-good">AI resolved</span>
                  ) : (
                    <span className="analytics-status is-bad">Escalated</span>
                  )}
                  {item.handoffReasonLabel && (
                    <span className="analytics-status">{item.handoffReasonLabel}</span>
                  )}
                </div>
                <div className="analytics-drawer-meta">
                  <span>{item.startedAt}</span>
                  {item.sourceUrl && <span>{item.sourceUrl}</span>}
                </div>
                {item.inboxAvailable ? (
                  <button
                    type="button"
                    className="analytics-row-button"
                    onClick={() => openConversation(item.conversationId)}
                  >
                    Open in inbox
                  </button>
                ) : (
                  <span className="analytics-card-sub">
                    AI-only conversation — not present in the human inbox.
                  </span>
                )}
              </div>
            ))}
        </div>
      </aside>
    </div>
  );
}

/* ------------------------------------------------------------------ *
 * Skeleton
 * ------------------------------------------------------------------ */

function AnalyticsSkeleton() {
  return (
    <div className="analytics" aria-busy="true" aria-live="polite">
      <span className="analytics-sr-only">Loading analytics…</span>
      <div className="analytics-kpis">
        {[0, 1, 2, 3, 4, 5, 6, 7].map((index) => (
          <div className="analytics-kpi" key={index}>
            <div className="analytics-skeleton" style={{ height: 12, width: '60%' }} />
            <div className="analytics-skeleton" style={{ height: 26, width: '45%' }} />
            <div className="analytics-skeleton" style={{ height: 12, width: '35%' }} />
          </div>
        ))}
      </div>
      <div className="analytics-card">
        <div className="analytics-skeleton" style={{ height: 240, width: '100%' }} />
      </div>
      <div className="analytics-grid-2">
        <div className="analytics-card">
          <div className="analytics-skeleton" style={{ height: 180 }} />
        </div>
        <div className="analytics-card">
          <div className="analytics-skeleton" style={{ height: 180 }} />
        </div>
      </div>
    </div>
  );
}

/* ------------------------------------------------------------------ *
 * Page
 * ------------------------------------------------------------------ */

function AnalyticsPage() {
  const workspaceId = useSelectedWorkspaceId();

  const [preset, setPreset] = useStateAnalytics('last_30_days');
  const [customFrom, setCustomFrom] = useStateAnalytics('');
  const [customTo, setCustomTo] = useStateAnalytics('');
  const [botId, setBotId] = useStateAnalytics('all');
  const [channelType, setChannelType] = useStateAnalytics('all');
  const [exportDataset, setExportDataset] = useStateAnalytics('summary');
  const [trendMetric, setTrendMetric] = useStateAnalytics('conversations');
  const [intelligenceTab, setIntelligenceTab] = useStateAnalytics('top');

  const [data, setData] = useStateAnalytics(null);
  const [loading, setLoading] = useStateAnalytics(true);
  const [error, setError] = useStateAnalytics('');
  const [drilldown, setDrilldown] = useStateAnalytics(null);

  const timezone = useMemoAnalytics(() => {
    try {
      return Intl.DateTimeFormat().resolvedOptions().timeZone || 'UTC';
    } catch (timezoneError) {
      return 'UTC';
    }
  }, []);

  const buildParams = useCallbackAnalytics(() => {
    const params = new URLSearchParams();
    if (workspaceId) params.set('workspaceId', workspaceId);
    params.set('preset', preset);
    params.set('timezone', timezone);
    if (preset === 'custom') {
      if (customFrom) params.set('from', customFrom);
      if (customTo) params.set('to', customTo);
    }
    if (botId !== 'all') params.set('botId', botId);
    if (channelType !== 'all') params.set('channelType', channelType);
    return params;
  }, [workspaceId, preset, timezone, customFrom, customTo, botId, channelType]);

  const load = useCallbackAnalytics(async () => {
    if (!workspaceId) return;
    if (preset === 'custom' && (!customFrom || !customTo)) return;

    setLoading(true);
    setError('');

    try {
      const response = await fetch(`/api/analytics/summary?${buildParams().toString()}`, {
        credentials: 'include',
        cache: 'no-store',
      });
      const payload = await response.json().catch(() => ({}));

      if (response.status === 401) {
        throw new Error('Your session has expired. Please log in again.');
      }
      if (response.status === 403) {
        throw new Error('You do not have permission to view analytics for this workspace.');
      }
      if (response.status === 404) {
        throw new Error('That workspace is no longer available. Choose another workspace.');
      }
      if (!response.ok || !payload.ok) {
        throw new Error(payload.error || 'Unable to load analytics right now.');
      }

      setData(payload);
    } catch (loadError) {
      setError(loadError.message || 'Unable to load analytics right now.');
    } finally {
      setLoading(false);
    }
  }, [workspaceId, preset, customFrom, customTo, buildParams]);

  useEffectAnalytics(() => {
    load();
  }, [load]);

  const openDrilldown = useCallbackAnalytics(
    async (title, subtitle, filters) => {
      setDrilldown({ title, subtitle, loading: true, error: '', conversations: [] });

      try {
        const params = buildParams();
        Object.entries(filters || {}).forEach(([key, value]) => {
          if (value !== undefined && value !== null && value !== '') {
            params.set(key, String(value));
          }
        });

        const response = await fetch(`/api/analytics/conversations?${params.toString()}`, {
          credentials: 'include',
          cache: 'no-store',
        });
        const payload = await response.json().catch(() => ({}));

        if (!response.ok || !payload.ok) {
          throw new Error(payload.error || 'Unable to load matching conversations.');
        }

        setDrilldown({
          title,
          subtitle,
          loading: false,
          error: '',
          conversations: payload.conversations || [],
        });
      } catch (drilldownError) {
        setDrilldown({
          title,
          subtitle,
          loading: false,
          error: drilldownError.message || 'Unable to load matching conversations.',
          conversations: [],
        });
      }
    },
    [buildParams],
  );

  const handleExport = () => {
    const params = buildParams();
    params.set('dataset', exportDataset);
    window.location.assign(`/api/analytics/export?${params.toString()}`);
  };

  if (!workspaceId) {
    return (
      <div className="analytics">
        <div className="analytics-onboarding">
          <h2>Select a workspace</h2>
          <p>Choose a workspace from the top bar to see its analytics.</p>
        </div>
      </div>
    );
  }

  if (loading && !data) return <AnalyticsSkeleton />;

  if (error && !data) {
    return (
      <div className="analytics">
        <div className="analytics-notice is-error" role="alert">
          <Icon name="alertTriangle" size={16} />
          <span>{error}</span>
          <span className="analytics-notice-actions">
            <button type="button" className="btn btn-secondary" onClick={load}>
              <Icon name="refresh" size={13} />
              Try again
            </button>
          </span>
        </div>
      </div>
    );
  }

  const metrics = data?.metrics || {};
  const definitions = data?.definitions || {};
  const range = data?.range || {};
  const filters = data?.filters || {};
  const breakdowns = data?.breakdowns || {};
  const questions = data?.questions || {};
  const aiUsage = data?.aiUsage || {};
  const warnings = data?.warnings || [];
  const insights = data?.insights || [];

  const hasAnyActivity =
    Number(metrics.conversations?.value || 0) > 0 ||
    Number(metrics.messages?.value || 0) > 0 ||
    Number(metrics.leads?.value || 0) > 0;

  const intelligenceRows =
    intelligenceTab === 'top'
      ? (questions.top || []).map((row) => ({
          id: row.question,
          text: row.question,
          total: row.total,
          filterKey: 'question',
        }))
      : intelligenceTab === 'low_confidence'
        ? (questions.lowConfidence || []).map((row) => ({
            id: row.topic,
            text: row.topic,
            total: row.total,
            filterKey: 'question',
            handoffReason: 'low_confidence',
          }))
        : intelligenceTab === 'negative'
          ? (questions.negativeSentiment || []).map((row) => ({
              id: row.topic,
              text: row.topic,
              total: row.total,
              filterKey: 'question',
              handoffReason: 'negative_sentiment',
            }))
          : (breakdowns.handoffReasons || []).map((row) => ({
              id: row.reason,
              text: row.label,
              total: row.total,
              filterKey: 'handoffReason',
              handoffReason: row.reason,
            }));

  return (
    <div className="analytics">
      <div className="analytics-head">
        <div>
          <h1>Analytics</h1>
          <div className="analytics-sub">
            {range.from} to {range.to} · {range.timezone} · compared with the previous {range.days}{' '}
            {range.days === 1 ? 'day' : 'days'}
          </div>
        </div>

        <div className="analytics-filters">
          <div className="analytics-field">
            <label htmlFor="analytics-preset">Date range</label>
            <select
              id="analytics-preset"
              className="analytics-select"
              value={preset}
              onChange={(event) => setPreset(event.target.value)}
            >
              {(filters.presets || []).map((item) => (
                <option key={item.key} value={item.key}>
                  {item.label}
                </option>
              ))}
            </select>
          </div>

          {preset === 'custom' && (
            <React.Fragment>
              <div className="analytics-field">
                <label htmlFor="analytics-from">From</label>
                <input
                  id="analytics-from"
                  type="date"
                  className="analytics-date"
                  value={customFrom}
                  max={customTo || undefined}
                  onChange={(event) => setCustomFrom(event.target.value)}
                />
              </div>
              <div className="analytics-field">
                <label htmlFor="analytics-to">To</label>
                <input
                  id="analytics-to"
                  type="date"
                  className="analytics-date"
                  value={customTo}
                  min={customFrom || undefined}
                  onChange={(event) => setCustomTo(event.target.value)}
                />
              </div>
            </React.Fragment>
          )}

          <div className="analytics-field">
            <label htmlFor="analytics-bot">Bot</label>
            <select
              id="analytics-bot"
              className="analytics-select"
              value={botId}
              onChange={(event) => setBotId(event.target.value)}
            >
              <option value="all">All bots</option>
              {(filters.availableBots || []).map((bot) => (
                <option key={bot.botId} value={bot.botId}>
                  {bot.botName}
                </option>
              ))}
            </select>
          </div>

          <div className="analytics-field">
            <label htmlFor="analytics-channel">Channel</label>
            <select
              id="analytics-channel"
              className="analytics-select"
              value={channelType}
              onChange={(event) => setChannelType(event.target.value)}
            >
              <option value="all">All channels</option>
              {(filters.availableChannels || []).map((channel) => (
                <option key={channel} value={channel}>
                  {channelLabel(channel)}
                </option>
              ))}
            </select>
          </div>

          <div className="analytics-field">
            <label htmlFor="analytics-export">Export</label>
            <select
              id="analytics-export"
              className="analytics-select"
              value={exportDataset}
              onChange={(event) => setExportDataset(event.target.value)}
            >
              {ANALYTICS_EXPORTS.map((item) => (
                <option key={item.value} value={item.value}>
                  {item.label}
                </option>
              ))}
            </select>
          </div>

          <button type="button" className="btn btn-primary" onClick={handleExport}>
            <Icon name="download" size={13} />
            Export CSV
          </button>
        </div>
      </div>

      {error && (
        <div className="analytics-notice is-error" role="alert">
          <Icon name="alertTriangle" size={15} />
          <span>{error} Showing the last successful load.</span>
          <span className="analytics-notice-actions">
            <button type="button" className="btn btn-secondary" onClick={load}>
              <Icon name="refresh" size={13} />
              Retry
            </button>
          </span>
        </div>
      )}

      {warnings.map((warning) => (
        <div className="analytics-notice" key={warning.code}>
          <Icon name="info" size={15} />
          <span>{warning.message}</span>
        </div>
      ))}

      {!hasAnyActivity ? (
        <div className="analytics-onboarding">
          <h2>No chatbot activity yet in this period</h2>
          <p>
            Once your chatbot is installed on your website and visitors start chatting, this page
            fills with real conversation, lead, containment and cost data. Nothing here is sample
            data — an empty period genuinely means no recorded activity.
          </p>
          <a className="btn btn-primary" href="/ai-builder">
            Set up and install your chatbot
            <Icon name="arrowRight" size={14} />
          </a>
        </div>
      ) : (
        <React.Fragment>
          <div className="analytics-kpis">
            {(data.overviewMetricKeys || []).map((key) => (
              <KpiCard key={key} metric={metrics[key]} definition={definitions[key]} />
            ))}
          </div>

          {insights.length > 0 && (
            <div className="analytics-insights">
              {insights.map((item) => (
                <article className={`analytics-insight is-${item.tone}`} key={item.id}>
                  <span className="analytics-insight-tone">
                    {item.tone === 'positive'
                      ? 'Working well'
                      : item.tone === 'negative'
                        ? 'Needs attention'
                        : 'Observation'}
                  </span>
                  <h3>{item.title}</h3>
                  <p>{item.detail}</p>
                </article>
              ))}
            </div>
          )}

          <div className="analytics-grid-2">
            <TrendChart
              points={data.timeseries || []}
              metricKey={trendMetric}
              metricKeys={data.timeseriesMetricKeys || []}
              definitions={definitions}
              onMetricChange={setTrendMetric}
            />
            <FunnelPanel steps={data.funnel || []} />
          </div>

          <div className="analytics-grid-3">
            <TablePanel
              title="By channel"
              subtitle="Where conversations happen"
              rows={breakdowns.byChannel}
              emptyMessage="No channel activity in this period."
              columns={[
                {
                  key: 'channel',
                  label: 'Channel',
                  render: (row) => (
                    <button
                      type="button"
                      className="analytics-row-button"
                      onClick={() =>
                        openDrilldown(
                          channelLabel(row.channelType),
                          `${row.conversations} conversations in this period`,
                          {},
                        )
                      }
                    >
                      {channelLabel(row.channelType)}
                    </button>
                  ),
                },
                { key: 'conversations', label: 'Convs', numeric: true, render: (row) => formatCount(row.conversations) },
                { key: 'contained', label: 'AI only', numeric: true, render: (row) => formatRate(row.containmentRate) },
              ]}
            />

            <TablePanel
              title="By bot"
              subtitle="Which assistant performs best"
              rows={breakdowns.byBot}
              emptyMessage="No bot activity in this period."
              columns={[
                { key: 'bot', label: 'Bot', render: (row) => <span className="analytics-truncate">{row.botName}</span> },
                { key: 'conversations', label: 'Convs', numeric: true, render: (row) => formatCount(row.conversations) },
                { key: 'leads', label: 'Leads', numeric: true, render: (row) => formatCount(row.leads) },
                { key: 'contained', label: 'AI only', numeric: true, render: (row) => formatRate(row.containmentRate) },
              ]}
            />

            <TablePanel
              title="By source page"
              subtitle={
                breakdowns.bySourcePage?.conversationsComplete
                  ? 'Where visitors convert'
                  : 'Lead counts are complete; conversation counts start from the analytics release'
              }
              rows={breakdowns.bySourcePage?.rows}
              emptyMessage="No page-level data recorded yet."
              columns={[
                {
                  key: 'page',
                  label: 'Page',
                  render: (row) => (
                    <button
                      type="button"
                      className="analytics-row-button"
                      onClick={() => openDrilldown(row.page, 'Conversations from this page', { sourcePage: row.page })}
                    >
                      <span className="analytics-truncate">{row.page}</span>
                    </button>
                  ),
                },
                { key: 'leads', label: 'Leads', numeric: true, render: (row) => formatCount(row.leads) },
                { key: 'rate', label: 'Conv.', numeric: true, render: (row) => formatRate(row.leadConversionRate) },
              ]}
            />
          </div>

          <section className="analytics-card">
            <div className="analytics-card-head">
              <div>
                <div className="analytics-card-title">Conversation intelligence</div>
                <div className="analytics-card-sub">
                  Classifications are stored when a conversation is handled — no AI runs when this
                  page loads.
                </div>
              </div>
              <div className="analytics-tabs" role="tablist" aria-label="Conversation intelligence view">
                {[
                  { key: 'top', label: 'Top questions' },
                  { key: 'low_confidence', label: 'Low confidence' },
                  { key: 'negative', label: 'Negative sentiment' },
                  { key: 'reasons', label: 'Handoff reasons' },
                ].map((tab) => (
                  <button
                    key={tab.key}
                    type="button"
                    role="tab"
                    className="analytics-tab"
                    aria-selected={intelligenceTab === tab.key}
                    onClick={() => setIntelligenceTab(tab.key)}
                  >
                    {tab.label}
                  </button>
                ))}
              </div>
            </div>

            {!intelligenceRows.length ? (
              <div className="analytics-empty">Nothing recorded for this view in the selected period.</div>
            ) : (
              <div className="analytics-table-scroll">
                <table className="analytics-table">
                  <thead>
                    <tr>
                      <th scope="col">{intelligenceTab === 'reasons' ? 'Reason' : 'Question'}</th>
                      <th scope="col" className="is-num">
                        Count
                      </th>
                    </tr>
                  </thead>
                  <tbody>
                    {intelligenceRows.map((row) => (
                      <tr key={row.id}>
                        <td>
                          <button
                            type="button"
                            className="analytics-row-button"
                            onClick={() =>
                              openDrilldown(
                                row.text,
                                `${row.total} matching conversations`,
                                row.filterKey === 'handoffReason'
                                  ? { handoffReason: row.handoffReason }
                                  : { question: row.text, handoffReason: row.handoffReason },
                              )
                            }
                          >
                            <span className="analytics-truncate">{row.text}</span>
                          </button>
                        </td>
                        <td className="is-num">{formatCount(row.total)}</td>
                      </tr>
                    ))}
                  </tbody>
                </table>
              </div>
            )}
          </section>

          <TablePanel
            title="Agent performance"
            subtitle="Human support workload and responsiveness"
            rows={data.agents}
            emptyMessage="No conversations have been handled by an agent in this period."
            columns={[
              { key: 'name', label: 'Agent', render: (row) => <span className="analytics-truncate">{row.name}</span> },
              { key: 'assigned', label: 'Assigned', numeric: true, render: (row) => formatCount(row.assignedConversations) },
              {
                key: 'first',
                label: 'First reply',
                numeric: true,
                render: (row) => (row.firstResponseSamples ? formatDuration(row.firstResponseMs) : '—'),
              },
              { key: 'replies', label: 'Replies', numeric: true, render: (row) => formatCount(row.replies) },
              { key: 'closed', label: 'Closed', numeric: true, render: (row) => formatCount(row.closedConversations) },
              { key: 'open', label: 'Open now', numeric: true, render: (row) => formatCount(row.openWorkload) },
            ]}
          />

          <div className="analytics-grid-2">
            <section className="analytics-card">
              <div className="analytics-card-head">
                <div>
                  <div className="analytics-card-title">AI operations</div>
                  <div className="analytics-card-sub">
                    Requests, reliability, latency and estimated spend
                  </div>
                </div>
              </div>

              <div className="analytics-kpis" style={{ gridTemplateColumns: 'repeat(2, minmax(0,1fr))' }}>
                <KpiCard metric={metrics.aiRequests} definition={definitions.aiRequests} />
                <KpiCard metric={metrics.aiSuccessRate} definition={definitions.aiSuccessRate} />
                <KpiCard metric={metrics.aiLatencyMs} definition={definitions.aiLatencyMs} />
                <KpiCard metric={metrics.totalTokens} definition={definitions.totalTokens} />
              </div>

              <p className="analytics-card-sub" style={{ marginTop: 12 }}>
                p95 latency {formatDuration(aiUsage.latency?.p95Ms)} across{' '}
                {formatCount(aiUsage.latency?.samples)} successful requests.
                {Number(metrics.estimatedCostUsd?.unpricedRequests || 0) > 0 &&
                  ` ${formatCount(metrics.estimatedCostUsd.unpricedRequests)} requests used a model with no configured price and contribute tokens but no cost.`}
              </p>

              {(aiUsage.byModel || []).length > 0 && (
                <div className="analytics-table-scroll" style={{ marginTop: 12 }}>
                  <table className="analytics-table">
                    <caption>Model breakdown</caption>
                    <thead>
                      <tr>
                        <th scope="col">Model</th>
                        <th scope="col" className="is-num">Requests</th>
                        <th scope="col" className="is-num">Tokens</th>
                        <th scope="col" className="is-num">Cost</th>
                      </tr>
                    </thead>
                    <tbody>
                      {aiUsage.byModel.map((row) => (
                        <tr key={row.model}>
                          <td><span className="analytics-truncate">{row.model}</span></td>
                          <td className="is-num">{formatCount(row.requests)}</td>
                          <td className="is-num">{formatCount(row.totalTokens)}</td>
                          <td className="is-num">${Number(row.estimatedCostUsd || 0).toFixed(4)}</td>
                        </tr>
                      ))}
                    </tbody>
                  </table>
                </div>
              )}

              {(aiUsage.errorCategories || []).length > 0 && (
                <div style={{ marginTop: 12, display: 'flex', gap: 6, flexWrap: 'wrap' }}>
                  {aiUsage.errorCategories.map((row) => (
                    <span className="analytics-status is-bad" key={row.category}>
                      {row.category.replace(/_/g, ' ')}: {row.total}
                    </span>
                  ))}
                </div>
              )}
            </section>

            <TablePanel
              title="Channel health"
              subtitle="Delivery status on connected messaging channels"
              rows={data.channels}
              emptyMessage="No messaging channels are connected to this workspace."
              columns={[
                {
                  key: 'channel',
                  label: 'Channel',
                  render: (row) => (
                    <span>
                      {channelLabel(row.channelType)}
                      <br />
                      <span
                        className={`analytics-status ${row.hasError ? 'is-bad' : 'is-good'}`}
                        style={{ marginTop: 4 }}
                      >
                        {row.hasError ? `Issue: ${row.lastErrorCategory}` : row.status}
                      </span>
                    </span>
                  ),
                },
                { key: 'in', label: 'In', numeric: true, render: (row) => formatCount(row.inboundMessages) },
                { key: 'out', label: 'Out', numeric: true, render: (row) => formatCount(row.outboundMessages) },
                { key: 'delivered', label: 'Delivered', numeric: true, render: (row) => formatCount(row.delivered) },
                { key: 'failed', label: 'Failed', numeric: true, render: (row) => formatCount(row.failed) },
              ]}
            />
          </div>
        </React.Fragment>
      )}

      <DrilldownDrawer state={drilldown} onClose={() => setDrilldown(null)} />
    </div>
  );
}

window.AnalyticsPage = AnalyticsPage;
