'use client';

import { useState, useEffect, useRef, useCallback } from 'react';
import GridLayout from 'react-grid-layout';
import type { Layout, LayoutItem } from 'react-grid-layout';
import 'react-grid-layout/css/styles.css';
import 'react-resizable/css/styles.css';
import { useApp } from '@/lib/context';
import { fetchCharts, createChart, updateChart, deleteChart, fetchSignals, fetchSessions, fetchUps } from '@/lib/api';
import type { ChartConfig, SignalRow, UpsRow, SessionBoundary, AlertConfig } from '@/lib/types';
import ChartCard from './ChartCard';
import ChartEditor from './ChartEditor';

const COLS       = 6;
const ROW_HEIGHT = 80;

interface Props {
  alerts: AlertConfig[];
}

export default function Dashboard({ alerts }: Props) {
  const { timeRange, timeMode, getFromTo } = useApp();
  const [charts,      setCharts]      = useState<ChartConfig[]>([]);
  const [signalData,  setSignalData]  = useState<Map<string, SignalRow[]>>(new Map());
  const [upsData,     setUpsData]     = useState<Map<string, UpsRow[]>>(new Map());
  const [sessions,    setSessions]    = useState<SessionBoundary[]>([]);
  const [editingChart,   setEditingChart]   = useState<ChartConfig | null>(null);
  const [creatingChart,  setCreatingChart]  = useState(false);
  const [containerWidth, setContainerWidth] = useState(1200);

  const containerRef    = useRef<HTMLDivElement>(null);
  const chartsRef       = useRef<ChartConfig[]>([]);
  const refreshingRef   = useRef(false);
  const layoutSaveTimer = useRef<ReturnType<typeof setTimeout> | null>(null);

  useEffect(() => { chartsRef.current = charts; }, [charts]);
  useEffect(() => { fetchCharts().then(setCharts); }, []);

  const refreshData = useCallback(async () => {
    if (refreshingRef.current) return;
    const current = chartsRef.current;
    if (current.length === 0) return;

    refreshingRef.current = true;
    try {
      const { from, to } = getFromTo();
      const signalCharts = current.filter(c => c.chart_type === 'signals');
      const upsCharts    = current.filter(c => c.chart_type === 'ups');

      if (signalCharts.length === 0 && upsCharts.length === 0) return;

      const [newSessions, ...results] = await Promise.all([
        fetchSessions(from, to),
        ...signalCharts.map(c => fetchSignals({
          combinator: c.filter_combinators ?? undefined,
          item:       c.filter_items       ?? undefined,
          exclude:    c.filter_items_exclude ?? undefined,
          signal:     c.signal_type,
          time_mode:  timeMode,
          from, to,
          regex:      c.filter_items_regex || undefined,
          ...(c.order_by !== 'time' ? { order_by: c.order_by, limit: c.series_limit } : {}),
        })),
        ...upsCharts.map(c => fetchUps({ combinator: c.filter_combinators?.[0], from, to })),
      ]);

      setSessions(newSessions as SessionBoundary[]);

      const sigMap = new Map<string, SignalRow[]>();
      signalCharts.forEach((c, i) => sigMap.set(c.id, results[i] as SignalRow[]));
      setSignalData(sigMap);

      const upsMap = new Map<string, UpsRow[]>();
      upsCharts.forEach((c, i) => upsMap.set(c.id, results[signalCharts.length + i] as UpsRow[]));
      setUpsData(upsMap);
    } finally {
      refreshingRef.current = false;
    }
  }, [getFromTo, timeMode]);

  useEffect(() => {
    if (charts.length > 0) refreshData();
  }, [charts, timeRange, timeMode, refreshData]);

  useEffect(() => {
    const id = setInterval(refreshData, 30_000);
    return () => clearInterval(id);
  }, [refreshData]);

  useEffect(() => {
    const el = containerRef.current;
    if (!el) return;
    setContainerWidth(el.clientWidth);
    const ro = new ResizeObserver(() => setContainerWidth(el.clientWidth));
    ro.observe(el);
    return () => ro.disconnect();
  }, []);

  async function handleCreate(draft: Omit<ChartConfig, 'id'>) {
    const created = await createChart(draft);
    setCharts(cs => [...cs, created]);
    setCreatingChart(false);
  }

  async function handleUpdate(id: string, draft: Omit<ChartConfig, 'id'>) {
    const updated = await updateChart(id, draft);
    setCharts(cs => cs.map(c => c.id === id ? updated : c));
    setEditingChart(null);
  }

  async function handleDelete(id: string) {
    await deleteChart(id);
    setCharts(cs => cs.filter(c => c.id !== id));
  }

  function handleLayoutChange(layout: Layout) {
    const items = layout as readonly LayoutItem[];
    const changed = items.filter(item => {
      const chart = chartsRef.current.find(c => c.id === item.i);
      return chart && (
        chart.pos_x !== item.x || chart.pos_y !== item.y ||
        chart.width !== item.w || chart.height !== item.h
      );
    });
    if (changed.length === 0) return;

    setCharts(cs => cs.map(c => {
      const l = changed.find(item => item.i === c.id);
      return l ? { ...c, pos_x: l.x, pos_y: l.y, width: l.w, height: l.h } : c;
    }));

    if (layoutSaveTimer.current) clearTimeout(layoutSaveTimer.current);
    layoutSaveTimer.current = setTimeout(() => {
      changed.forEach(item =>
        updateChart(item.i, { pos_x: item.x, pos_y: item.y, width: item.w, height: item.h }),
      );
    }, 500);
  }

  const layout: Layout = charts.map(c => ({
    i: c.id, x: c.pos_x, y: c.pos_y, w: c.width, h: c.height,
    minW: 1,
    minH: c.chart_type === 'divider' ? 1 : 2,
  }));

  return (
    <div ref={containerRef} className="w-full">
      <GridLayout
        layout={layout}
        width={containerWidth}
        onLayoutChange={handleLayoutChange}
        gridConfig={{ cols: COLS, rowHeight: ROW_HEIGHT, margin: [8, 8] }}
        dragConfig={{ handle: '.drag-handle' }}
        resizeConfig={{
          handleComponent: (axis, ref) => (
            <span ref={ref}
              className="react-resizable-handle react-resizable-handle-se"
              style={{
                borderRight: '3px solid #4b5563',
                borderBottom: '3px solid #4b5563',
                opacity: 0.6,
              }}
            />
          ),
        }}
      >
        {charts.map(c => (
          <div key={c.id} className="drag-handle cursor-grab active:cursor-grabbing">
            <ChartCard
              config={c}
              rows={signalData.get(c.id) ?? []}
              upsRows={upsData.get(c.id) ?? []}
              sessions={sessions}
              alerts={alerts.filter(a =>
                !c.filter_combinators || !a.combinator ||
                c.filter_combinators.includes(a.combinator),
              )}
              timeMode={timeMode}
              onEdit={() => setEditingChart(c)}
              onDelete={() => handleDelete(c.id)}
            />
          </div>
        ))}
      </GridLayout>

      <button
        onClick={() => setCreatingChart(true)}
        className="fixed bottom-6 right-6 w-12 h-12 bg-indigo-600 hover:bg-indigo-500 text-white rounded-full text-2xl shadow-lg flex items-center justify-center z-30"
      >
        +
      </button>

      {creatingChart && (
        <ChartEditor onSave={handleCreate} onClose={() => setCreatingChart(false)} />
      )}
      {editingChart && (
        <ChartEditor
          initial={editingChart}
          onSave={draft => handleUpdate(editingChart.id, draft)}
          onClose={() => setEditingChart(null)}
        />
      )}
    </div>
  );
}