"use client";

import { useEffect, useState } from "react";
import {
  DndContext,
  DragOverlay,
  KeyboardSensor,
  PointerSensor,
  closestCenter,
  useSensor,
  useSensors,
  type DragEndEvent,
  type DragStartEvent,
} from "@dnd-kit/core";
import {
  SortableContext,
  arrayMove,
  rectSwappingStrategy,
  sortableKeyboardCoordinates,
  useSortable,
} from "@dnd-kit/sortable";
import { CSS } from "@dnd-kit/utilities";
import { useQueryClient } from "@tanstack/react-query";
import { Plus, RefreshCw, RotateCw, SlidersHorizontal } from "lucide-react";
import { Button } from "@/components/ui/button";
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";
import { Skeleton } from "@/components/ui/skeleton";
import { Switch } from "@/components/ui/switch";
import {
  DropdownMenu,
  DropdownMenuContent,
  DropdownMenuItem,
  DropdownMenuTrigger,
} from "@/components/ui/dropdown-menu";
import { useI18n, useT } from "@/i18n";
import { queryKeys } from "@/lib/query-keys";
import { cn } from "@/lib/cn";
import { formatRelative } from "@/lib/format";
import { setAutoRefresh, useAutoRefresh } from "./auto-refresh";
import { useDashboardStats } from "./overview-data";
import { WidgetErrorBoundary } from "./widget-error-boundary";
import {
  WIDGET_COMPONENTS,
  widgetRegistry,
} from "./widgets/registry";
import { TONE_CLASSES } from "./widgets/shared";
import { WidgetShell } from "./widgets/widget-shell";
import {
  WIDGET_SIZE_CLASSES,
  normalizeWidgetConfig,
  type WidgetConfig,
  type WidgetId,
} from "./widgets/types";

const STORAGE_KEY = "kapitano.dashboard.widgets.v1";

function loadConfig(): WidgetConfig {
  if (typeof window === "undefined") return normalizeWidgetConfig(null);
  try {
    const raw = localStorage.getItem(STORAGE_KEY);
    return normalizeWidgetConfig(raw ? JSON.parse(raw) : null);
  } catch {
    return normalizeWidgetConfig(null);
  }
}

export function WidgetGrid() {
  const t = useT();
  const { locale } = useI18n();
  const queryClient = useQueryClient();
  const autoRefresh = useAutoRefresh();
  const statsQuery = useDashboardStats();

  const [config, setConfig] = useState<WidgetConfig>(loadConfig);
  const [editMode, setEditMode] = useState(false);
  const [activeId, setActiveId] = useState<WidgetId | null>(null);

  useEffect(() => {
    try {
      localStorage.setItem(STORAGE_KEY, JSON.stringify(config));
    } catch {
      // storage unavailable — layout just won't persist
    }
  }, [config]);

  const sensors = useSensors(
    useSensor(PointerSensor, { activationConstraint: { distance: 6 } }),
    useSensor(KeyboardSensor, { coordinateGetter: sortableKeyboardCoordinates }),
  );

  function handleDragStart(event: DragStartEvent) {
    setActiveId(event.active.id as WidgetId);
  }

  function handleDragEnd(event: DragEndEvent) {
    setActiveId(null);
    const { active, over } = event;
    if (!over || active.id === over.id) return;
    const oldIndex = config.order.indexOf(active.id as WidgetId);
    const newIndex = config.order.indexOf(over.id as WidgetId);
    if (oldIndex < 0 || newIndex < 0) return;
    setConfig((c) => ({ ...c, order: arrayMove(c.order, oldIndex, newIndex) }));
  }

  function removeWidget(id: WidgetId) {
    setConfig((c) => ({
      order: c.order.filter((x) => x !== id),
      hidden: c.hidden.includes(id) ? c.hidden : [...c.hidden, id],
    }));
  }

  function addWidget(id: WidgetId) {
    setConfig((c) => ({
      hidden: c.hidden.filter((x) => x !== id),
      order: c.order.includes(id) ? c.order : [...c.order, id],
    }));
  }

  function resetLayout() {
    setConfig(normalizeWidgetConfig(null));
  }

  function refreshAll() {
    void queryClient.refetchQueries({ queryKey: queryKeys.stats });
    void queryClient.refetchQueries({ queryKey: ["orders", "list"] });
    void queryClient.refetchQueries({ queryKey: ["drivers", "list"] });
  }

  const visible = config.order;
  const hidden = config.hidden;
  const activeMeta = activeId ? widgetRegistry[activeId] : null;
  const lastUpdatedAt = statsQuery.data?.generated_at;
  const isFirstLoad = statsQuery.isLoading && lastUpdatedAt === undefined;

  return (
    <div>
      <div className="mb-4 flex flex-wrap items-center justify-between gap-2">
        <div className="flex flex-wrap items-center gap-2">
          <Button variant="ghost" size="sm" onClick={refreshAll} className="gap-1.5">
            <RotateCw className="h-3.5 w-3.5" aria-hidden />
            {t("widgets.refresh")}
          </Button>
          {lastUpdatedAt ? (
            <span className="inline-flex items-center gap-1.5 text-xs text-muted-foreground">
              {statsQuery.isFetching ? (
                <RefreshCw className="h-3 w-3 animate-spin" aria-hidden />
              ) : null}
              {t("widgets.lastUpdated", { time: formatRelative(lastUpdatedAt, locale) })}
            </span>
          ) : null}
          <label className="flex cursor-pointer items-center gap-1.5 text-xs text-muted-foreground">
            <Switch
              checked={autoRefresh}
              onCheckedChange={(value) => setAutoRefresh(Boolean(value))}
              aria-label={t("widgets.autoRefresh")}
            />
            {t("widgets.autoRefresh")}
          </label>
        </div>

        <div className="flex items-center gap-2">
          {editMode ? (
            <>
              <DropdownMenu>
                <DropdownMenuTrigger asChild>
                  <Button variant="outline" size="sm" disabled={hidden.length === 0} className="gap-1.5">
                    <Plus className="h-3.5 w-3.5" aria-hidden />
                    {t("widgets.add")}
                  </Button>
                </DropdownMenuTrigger>
                <DropdownMenuContent align="end" className="w-60">
                  {hidden.map((id) => {
                    const meta = widgetRegistry[id];
                    const Icon = meta.icon;
                    return (
                      <DropdownMenuItem key={id} onSelect={() => addWidget(id)}>
                        <Icon className="h-4 w-4 text-muted-foreground" aria-hidden />
                        {t(meta.titleKey)}
                      </DropdownMenuItem>
                    );
                  })}
                </DropdownMenuContent>
              </DropdownMenu>
              <Button variant="outline" size="sm" onClick={resetLayout}>
                {t("widgets.reset")}
              </Button>
            </>
          ) : null}

          <Button
            variant={editMode ? "default" : "outline"}
            size="sm"
            onClick={() => setEditMode((v) => !v)}
            className="gap-1.5"
          >
            <SlidersHorizontal className="h-3.5 w-3.5" aria-hidden />
            {editMode ? t("widgets.done") : t("widgets.customize")}
          </Button>
        </div>
      </div>

      {isFirstLoad ? (
        <WidgetGridSkeleton />
      ) : visible.length === 0 ? (
        <Card className="border-dashed">
          <CardHeader className="items-center gap-2 py-10 text-center">
            <CardTitle className="text-muted-foreground">{t("widgets.gridEmpty")}</CardTitle>
            <Button variant="outline" size="sm" onClick={() => setEditMode(true)} className="gap-1.5">
              <Plus className="h-3.5 w-3.5" aria-hidden />
              {t("widgets.add")}
            </Button>
          </CardHeader>
        </Card>
      ) : (
        <DndContext
          sensors={sensors}
          collisionDetection={closestCenter}
          onDragStart={handleDragStart}
          onDragEnd={handleDragEnd}
          onDragCancel={() => setActiveId(null)}
        >
          <div className="grid grid-cols-1 gap-4 sm:grid-cols-12">
            <SortableContext items={visible} strategy={rectSwappingStrategy}>
              {visible.map((id) => (
                <SortableWidgetCard key={id} id={id} editMode={editMode} onRemove={() => removeWidget(id)} />
              ))}
            </SortableContext>
          </div>
          <DragOverlay dropAnimation={{ duration: 150, easing: "cubic-bezier(0.2, 0, 0, 1)" }}>
            {activeMeta ? (
              <Card className="w-72 shadow-[0_12px_32px_rgba(27,18,85,0.18)]">
                <CardHeader className="flex-row items-center gap-2.5 space-y-0">
                  <span className={cn("flex h-9 w-9 shrink-0 items-center justify-center rounded-lg", TONE_CLASSES[activeMeta.tone])} aria-hidden>
                    <activeMeta.icon className="h-[18px] w-[18px]" strokeWidth={2.1} />
                  </span>
                  <CardTitle className="text-sm">{t(activeMeta.titleKey)}</CardTitle>
                </CardHeader>
              </Card>
            ) : null}
          </DragOverlay>
        </DndContext>
      )}
    </div>
  );
}

function SortableWidgetCard({
  id,
  editMode,
  onRemove,
}: {
  id: WidgetId;
  editMode: boolean;
  onRemove: () => void;
}) {
  const meta = widgetRegistry[id];
  const Body = WIDGET_COMPONENTS[id];
  const { attributes, listeners, setNodeRef, transform, transition, isDragging } = useSortable({ id });

  return (
    <div
      ref={setNodeRef}
      style={{ transform: CSS.Transform.toString(transform), transition }}
      className={cn(
        "col-span-1",
        WIDGET_SIZE_CLASSES[meta.size],
        isDragging && "z-20 opacity-60",
      )}
    >
      <WidgetShell
        meta={meta}
        editMode={editMode}
        onRemove={onRemove}
        dragHandleAttributes={editMode ? attributes : undefined}
        dragHandleListeners={editMode ? listeners : undefined}
      >
        <WidgetErrorBoundary identifier={meta.titleKey}>
          <Body />
        </WidgetErrorBoundary>
      </WidgetShell>
    </div>
  );
}

function WidgetGridSkeleton() {
  return (
    <div className="grid grid-cols-1 gap-4 sm:grid-cols-12" aria-hidden>
      {[0, 1, 2].map((i) => (
        <Card key={i} className="col-span-1 sm:col-span-6 xl:col-span-4">
          <CardHeader className="flex-row items-center gap-2.5 space-y-0 pb-3">
            <Skeleton className="h-9 w-9 shrink-0 rounded-lg" />
            <div className="min-w-0 space-y-1.5">
              <Skeleton className="h-4 w-24" />
              <Skeleton className="h-3 w-32" />
            </div>
          </CardHeader>
          <CardContent className="space-y-3">
            <Skeleton className="h-8 w-2/3" />
            <Skeleton className="h-4 w-full" />
            <Skeleton className="h-4 w-4/5" />
          </CardContent>
        </Card>
      ))}
    </div>
  );
}