import { useCallback, useEffect, useMemo, useState } from 'react';
import GridLayout from 'react-grid-layout';
import 'react-grid-layout/css/styles.css';
import 'react-resizable/css/styles.css';
import { AnalyticsApi, LayoutApi, ExportApi, SyncApi } from '../api/client.js';
import SyncSplash from '../components/SyncSplash.jsx';
import {
  HealthWidget, StatCard, TopSendersWidget, VolumeWidget,
  CategoryHeatmapWidget, AttachmentsWidget, StorageWidget
} from '../components/widgets.jsx';

// Default grid geometry; overridden by the user's saved layout.
const DEFAULT_LAYOUT = [
  { i: 'inbox-health', x: 0, y: 0, w: 3, h: 5 },
  { i: 'total-emails', x: 3, y: 0, w: 2, h: 2 },
  { i: 'unread-emails', x: 5, y: 0, w: 2, h: 2 },
  { i: 'storage', x: 7, y: 0, w: 2, h: 2 },
  { i: 'top-senders', x: 3, y: 2, w: 3, h: 5 },
  { i: 'volume', x: 6, y: 2, w: 6, h: 4 },
  { i: 'category-heatmap', x: 0, y: 5, w: 6, h: 5 },
  { i: 'attachments', x: 6, y: 6, w: 4, h: 4 },
];

const ALL_WIDGETS = DEFAULT_LAYOUT.map((l) => l.i);

export default function Dashboard() {
  const [data, setData] = useState(null);
  const [layout, setLayout] = useState(DEFAULT_LAYOUT);
  const [hidden, setHidden] = useState([]);
  const [syncing, setSyncing] = useState(false);

  const loadData = useCallback(() => {
    AnalyticsApi.dashboard().then(setData).catch(() => {});
  }, []);

  useEffect(() => {
    LayoutApi.get().then((saved) => {
      if (saved?.length) {
        const savedLayout = saved.map((w) => ({ i: w.widgetKey, x: w.x, y: w.y, w: w.w, h: w.h }));
        const savedKeys = new Set(savedLayout.map((l) => l.i));
        // Append any newer default widgets the saved layout doesn't know about yet.
        const merged = [...savedLayout, ...DEFAULT_LAYOUT.filter((d) => !savedKeys.has(d.i))];
        setLayout(merged);
        setHidden(saved.filter((w) => !w.visible).map((w) => w.widgetKey));
      }
    }).catch(() => {});

    // Decide whether to show the loading splash: if a sync is running, watch it;
    // if the inbox has never been synced, kick one off automatically.
    SyncApi.status().then((s) => {
      if (s.isRunning) {
        setSyncing(true);
      } else if (!s.lastSuccessfulSyncUtc) {
        SyncApi.incremental().then(() => setSyncing(true)).catch(loadData);
      } else {
        loadData();
      }
    }).catch(loadData);
  }, [loadData]);

  // Show the splash when a sync is triggered from the header "Sync now" button.
  useEffect(() => {
    const onStart = () => setSyncing(true);
    window.addEventListener('inboxintel:sync-started', onStart);
    return () => window.removeEventListener('inboxintel:sync-started', onStart);
  }, []);

  const onSyncDone = useCallback(() => {
    setSyncing(false);
    loadData();
  }, [loadData]);

  const persist = (nextLayout, nextHidden) => {
    const dto = nextLayout.map((l, idx) => ({
      widgetKey: l.i, x: l.x, y: l.y, w: l.w, h: l.h,
      visible: !nextHidden.includes(l.i), sortOrder: idx, settingsJson: null
    }));
    LayoutApi.save(dto).catch(() => {});
  };

  const onLayoutChange = (l) => { setLayout(l); persist(l, hidden); };
  const toggle = (key) => {
    const next = hidden.includes(key) ? hidden.filter((h) => h !== key) : [...hidden, key];
    setHidden(next); persist(layout, next);
  };

  const visibleLayout = useMemo(() => layout.filter((l) => !hidden.includes(l.i)), [layout, hidden]);

  const render = (key) => {
    switch (key) {
      case 'inbox-health': return <HealthWidget health={data?.health} />;
      case 'total-emails': return <StatCard label="Total Emails" value={(data?.totalEmails ?? 0).toLocaleString()} to="/app/folder/allmail" />;
      case 'unread-emails': return <StatCard label="Unread" value={(data?.unreadEmails ?? 0).toLocaleString()} to="/app/folder/unread" />;
      case 'storage': return <StorageWidget bytes={data?.storageEstimateBytes} />;
      case 'top-senders': return <TopSendersWidget senders={data?.topSenders} />;
      case 'volume': return <VolumeWidget volume={data?.volumeOverTime} />;
      case 'category-heatmap': return <CategoryHeatmapWidget />;
      case 'attachments': return <AttachmentsWidget attachments={data?.attachmentBreakdown} />;
      default: return null;
    }
  };

  return (
    <div className="dashboard">
      {syncing && <SyncSplash onDone={onSyncDone} />}
      <div className="toolbar">
        <div className="widget-toggles">
          {ALL_WIDGETS.map((k) => (
            <label key={k}>
              <input type="checkbox" checked={!hidden.includes(k)} onChange={() => toggle(k)} /> {k}
            </label>
          ))}
        </div>
        <div className="spacer" />
        <a className="btn" href={ExportApi.reportUrl('pdf')}>Export PDF</a>
        <a className="btn" href={ExportApi.reportUrl('csv')}>CSV</a>
        <a className="btn" href={ExportApi.reportUrl('json')}>JSON</a>
      </div>

      <GridLayout
        className="layout"
        layout={visibleLayout}
        cols={12}
        rowHeight={60}
        width={1200}
        isResizable
        isDraggable
        resizeHandles={['se']}
        compactType="vertical"
        margin={[12, 12]}
        onLayoutChange={onLayoutChange}
        draggableHandle=".widget h3, .widget .stat-label"
      >
        {visibleLayout.map((l) => (
          <div key={l.i} className="grid-item">{render(l.i)}</div>
        ))}
      </GridLayout>
    </div>
  );
}
