"use client";

import { useState, useEffect, use, useCallback, useRef } from "react";
import { useRouter } from "next/navigation";
import Link from "next/link";
import {
  GripIcon,
  PencilIcon,
  PlusIcon,
  Trash2Icon,
  RefreshCwIcon,
  LayoutGridIcon,
} from "lucide-react";
import {
  getDashboard,
  createWidget,
  deleteWidget,
  updateWidget,
  getWidgetData,
  getViews,
  getTeams,
  updateDashboard,
} from "@/lib/api";
import type {
  Dashboard,
  DashboardWidget,
  SavedView,
  Team,
  WidgetData,
} from "@/lib/types";
import { Button } from "@/components/ui/button";
import {
  Dialog,
  DialogContent,
  DialogDescription,
  DialogFooter,
  DialogHeader,
  DialogTitle,
} from "@/components/ui/dialog";
import { CountWidget } from "@/components/widgets/count-widget";
import { TicketListWidget } from "@/components/widgets/ticket-list-widget";
import { StatusChartWidget } from "@/components/widgets/status-chart-widget";
import { GroupedCountsWidget } from "@/components/widgets/grouped-counts-widget";
import { cn } from "@/lib/utils";

function widgetGridStyle(position: { x: number; y: number; w: number; h: number }) {
  return {
    gridColumn: `${position.x + 1} / span ${position.w}`,
    gridRow: `${position.y + 1} / span ${position.h}`,
  };
}

export default function DashboardPage({ params }: { params: Promise<{ id: string }> }) {
  const { id } = use(params);
  const router = useRouter();

  const [dashboard, setDashboard] = useState<Dashboard | null>(null);
  const [widgets, setWidgets] = useState<(DashboardWidget & { data?: WidgetData })[]>([]);
  const [views, setViews] = useState<SavedView[]>([]);
  const [loading, setLoading] = useState(true);
  const [error, setError] = useState<string | null>(null);
  const [autoRefresh, setAutoRefresh] = useState(false);
  const [editMode, setEditMode] = useState(false);
  const [teams, setTeams] = useState<Team[]>([]);

  // Add widget dialog
  const [addOpen, setAddOpen] = useState(false);
  const [addViewId, setAddViewId] = useState("");
  const [addTitle, setAddTitle] = useState("");
  const [addType, setAddType] = useState("count");
  const [addGroupBy, setAddGroupBy] = useState("owner");
  const [adding, setAdding] = useState(false);

  const fetchDashboard = useCallback(async () => {
    const { data, error } = await getDashboard(id);
    if (error || !data) {
      setError(error ?? "Dashboard not found");
      setLoading(false);
      return;
    }
    setDashboard(data);
    const widgetList = data.widgets ?? [];
    setWidgets(widgetList);

    // Fetch data for each widget
    for (const widget of widgetList) {
      const { data: wData } = await getWidgetData(id, widget.id);
      if (wData) {
        setWidgets((prev) =>
          prev.map((w) => (w.id === widget.id ? { ...w, data: wData } : w))
        );
      }
    }

    setLoading(false);
  }, [id]);

  useEffect(() => {
    fetchDashboard();
    getViews().then(({ data }) => { if (data) setViews(data); });
    getTeams().then(({ data }) => { if (data) setTeams(data); });
  }, [fetchDashboard]);

  // Auto-refresh: only refresh widget data, not structure
  useEffect(() => {
    if (!autoRefresh || !dashboard) return;
    const interval = setInterval(() => {
      for (const widget of widgets) {
        getWidgetData(dashboard.id, widget.id).then(({ data: wData }) => {
          if (wData) {
            setWidgets((prev) =>
              prev.map((w) => (w.id === widget.id ? { ...w, data: wData } : w))
            );
          }
        });
      }
    }, 30_000);
    return () => clearInterval(interval);
  }, [autoRefresh, dashboard?.id]);

  const handleAddWidget = async () => {
    if (!addViewId || !addTitle.trim()) return;
    setAdding(true);
    // Smart positioning: fill a 3-column grid (4 units each in 12-col grid)
    const COLS = 3; const W = 4; const H = 2;
    const occupied = new Set(widgets.map((w) => `${w.position.x},${w.position.y}`));
    let x = 0; let y = 0;
    while (occupied.has(`${x},${y}`)) {
      x += W;
      if (x >= COLS * W) { x = 0; y += H; }
    }
    const pos = { x, y, w: W, h: H };
    const config = addType === "grouped_counts" ? { group_by: addGroupBy } : {};
    const { data, error } = await createWidget(id, {
      view_id: addViewId,
      title: addTitle.trim(),
      widget_type: addType,
      position: pos,
      config,
    });
    if (!error && data) {
      setWidgets((prev) => [...prev, data]);
      const { data: wData } = await getWidgetData(id, data.id);
      if (wData) {
        setWidgets((prev) => prev.map((w) => (w.id === data.id ? { ...w, data: wData } : w)));
      }
      setAddOpen(false);
      setAddViewId("");
      setAddTitle("");
      setAddType("count");
    }
    setAdding(false);
  };

  const handleDeleteWidget = async (widgetId: string) => {
    await deleteWidget(id, widgetId);
    setWidgets((prev) => prev.filter((w) => w.id !== widgetId));
  };

  const gridRef = useRef<HTMLDivElement>(null);
  const [resizingId, setResizingId] = useState<string | null>(null);
  const [draggingId, setDraggingId] = useState<string | null>(null);

  // Resize: track mousedown → mousemove → mouseup
  const handleResizeStart = (e: React.MouseEvent, widgetId: string) => {
    e.preventDefault();
    e.stopPropagation();
    setResizingId(widgetId);
    const startX = e.clientX;
    const startY = e.clientY;
    const widget = widgets.find((w) => w.id === widgetId);
    if (!widget || !gridRef.current) return;

    const startW = widget.position.w;
    const startH = widget.position.h;
    const gridWidth = gridRef.current.offsetWidth;
    const unitSize = gridWidth / 12;

    const onMove = (ev: MouseEvent) => {
      const dx = Math.round((ev.clientX - startX) / unitSize);
      const dy = Math.round((ev.clientY - startY) / unitSize);
      const newW = Math.max(1, Math.min(12, startW + dx));
      const newH = Math.max(1, startH + dy);
      setWidgets((prev) =>
        prev.map((w) =>
          w.id === widgetId
            ? { ...w, position: { ...w.position, w: newW, h: newH } }
            : w
        )
      );
    };

    const onUp = async () => {
      document.removeEventListener("mousemove", onMove);
      document.removeEventListener("mouseup", onUp);
      setResizingId(null);
      const updated = widgets.find((w) => w.id === widgetId);
      if (updated) {
        await updateWidget(id, widgetId, { position: updated.position });
      }
    };

    document.addEventListener("mousemove", onMove);
    document.addEventListener("mouseup", onUp);
  };

  // Drag: HTML5 DnD
  const handleDragStart = (e: React.DragEvent, widgetId: string) => {
    setDraggingId(widgetId);
    e.dataTransfer.setData("text/plain", widgetId);
    e.dataTransfer.effectAllowed = "move";
  };

  const handleDragOver = (e: React.DragEvent) => {
    e.preventDefault();
    e.dataTransfer.dropEffect = "move";
  };

  const handleDrop = async (e: React.DragEvent, targetId: string) => {
    e.preventDefault();
    const sourceId = e.dataTransfer.getData("text/plain");
    if (!sourceId || sourceId === targetId) { setDraggingId(null); return; }

    const source = widgets.find((w) => w.id === sourceId);
    const target = widgets.find((w) => w.id === targetId);
    if (!source || !target) { setDraggingId(null); return; }

    // Swap positions
    const sourcePos = { ...source.position };
    const targetPos = { ...target.position };

    setWidgets((prev) =>
      prev.map((w) => {
        if (w.id === sourceId) return { ...w, position: targetPos };
        if (w.id === targetId) return { ...w, position: sourcePos };
        return w;
      })
    );

    await updateWidget(id, sourceId, { position: targetPos });
    await updateWidget(id, targetId, { position: sourcePos });
    setDraggingId(null);
  };

  const handleDragEnd = () => {
    setDraggingId(null);
  };

  const renderWidget = (widget: DashboardWidget & { data?: WidgetData }) => {
    if (!widget.data) {
      return (
        <div className="flex h-full items-center justify-center rounded-lg border border-border bg-card p-4">
          <div className="h-4 w-4 animate-spin rounded-full border-2 border-primary border-t-transparent" />
        </div>
      );
    }

    switch (widget.data.type) {
      case "count":
        return <CountWidget data={widget.data} />;
      case "ticket_list":
        return <TicketListWidget data={widget.data} />;
      case "status_chart":
        return <StatusChartWidget data={widget.data} />;
      case "grouped_counts":
        return <GroupedCountsWidget data={widget.data} />;
      default:
        return (
          <div className="flex h-full items-center justify-center rounded-lg border border-border bg-card p-4">
            <p className="text-xs text-muted-foreground">Unknown type: {widget.data.type}</p>
          </div>
        );
    }
  };

  if (loading) {
    return (
      <div className="flex h-full items-center justify-center">
        <div className="h-8 w-8 animate-spin rounded-full border-2 border-primary border-t-transparent" />
      </div>
    );
  }

  if (error || !dashboard) {
    return (
      <div className="flex h-full flex-col items-center justify-center gap-4">
        <p className="text-sm text-muted-foreground">{error ?? "Dashboard not found"}</p>
        <Link href="/" className="text-sm text-primary hover:underline">
          Go to ticket list
        </Link>
      </div>
    );
  }

  return (
    <div className="flex h-full flex-col bg-background/80">
      <header className="shrink-0 border-b border-border bg-card/82 backdrop-blur">
        <div className="flex items-center justify-between px-5 py-3 lg:px-6">
          <div className="min-w-0">
            <div className="flex items-center gap-2 text-[11px] font-semibold uppercase text-muted-foreground">
              <LayoutGridIcon className="h-3.5 w-3.5" />
              Dashboard
            </div>
            <h1 className="mt-1 text-xl font-semibold text-foreground">{dashboard.name}</h1>
            <div className="mt-2 flex items-center gap-2">
              <select
                value={dashboard.team_id ?? ""}
                onChange={async (e) => {
                  const teamId = e.target.value || null;
                  await updateDashboard(dashboard.id, { team_id: teamId });
                  setDashboard((prev) => prev ? { ...prev, team_id: teamId } : prev);
                }}
                className="h-7 rounded border border-border bg-card px-2 text-xs text-muted-foreground outline-none"
              >
                <option value="">No team</option>
                {teams.map((t) => (
                  <option key={t.id} value={t.id}>{t.name}</option>
                ))}
              </select>
              {dashboard.description && (
                <p className="text-sm text-muted-foreground">{dashboard.description}</p>
              )}
            </div>
          </div>
          <div className="flex items-center gap-2">
            <Button
              variant="outline"
              size="sm"
              onClick={() => setEditMode((v) => !v)}
              className={cn("h-8 border-border/80", editMode ? "bg-primary/20 text-primary border-primary/40" : "bg-card/70")}
            >
              <PencilIcon className="h-4 w-4" />
              {editMode ? "Done" : "Edit"}
            </Button>
            <Button
              variant="outline"
              size="sm"
              onClick={() => setAutoRefresh((v) => !v)}
              className={cn("h-8 border-border/80", autoRefresh ? "bg-primary/20 text-primary" : "bg-card/70")}
            >
              <RefreshCwIcon className={cn("h-4 w-4", autoRefresh && "animate-spin")} />
              {autoRefresh ? "Live" : "Auto"}
            </Button>
            <Button
              variant="outline"
              size="sm"
              onClick={fetchDashboard}
              className="h-8 border-border/80 bg-card/70"
            >
              <RefreshCwIcon className="h-4 w-4" />
              Refresh
            </Button>
            {editMode && (
              <Button size="sm" onClick={() => setAddOpen(true)} className="h-8 bg-primary shadow-sm">
                <PlusIcon className="h-4 w-4" />
                Add widget
              </Button>
            )}
          </div>
        </div>
      </header>

      <div className="flex-1 overflow-auto p-5 lg:p-6">
        {widgets.length === 0 ? (
          <div className="flex h-full flex-col items-center justify-center gap-3">
            <LayoutGridIcon className="h-10 w-10 text-muted-foreground/40" />
            <p className="text-sm text-muted-foreground">No widgets yet</p>
            {editMode ? (
              <Button variant="outline" size="sm" onClick={() => setAddOpen(true)}>
                <PlusIcon className="h-4 w-4" />
                Add your first widget
              </Button>
            ) : (
              <Button variant="outline" size="sm" onClick={() => setEditMode(true)}>
                <PencilIcon className="h-4 w-4" />
                Enter edit mode
              </Button>
            )}
          </div>
        ) : (
          <div
            ref={gridRef}
            className="grid auto-rows-[minmax(100px,auto)] grid-cols-6 gap-3 md:grid-cols-12 md:gap-4"
          >
            {widgets.map((widget) => (
              <div
                key={widget.id}
                className={cn(
                  "group relative",
                  editMode && "cursor-grab",
                  draggingId === widget.id && "opacity-50",
                  resizingId === widget.id && "select-none",
                )}
                style={widgetGridStyle(widget.position)}
                draggable={editMode}
                onDragStart={(e) => editMode && handleDragStart(e, widget.id)}
                onDragOver={handleDragOver}
                onDrop={(e) => handleDrop(e, widget.id)}
                onDragEnd={handleDragEnd}
              >
                {/* Drag handle */}
                {editMode && (
                  <div className="absolute left-2 top-2 z-10 hidden h-6 w-6 cursor-grab items-center justify-center rounded bg-background/80 text-muted-foreground group-hover:flex">
                    <GripIcon className="h-3.5 w-3.5" />
                  </div>
                )}
                {renderWidget(widget)}
                {editMode && (
                  <>
                    <button
                      type="button"
                      onClick={() => handleDeleteWidget(widget.id)}
                      className="absolute right-2 top-2 z-10 hidden h-6 w-6 items-center justify-center rounded bg-destructive/90 text-destructive-foreground transition-opacity hover:bg-destructive group-hover:flex"
                      title="Remove widget"
                    >
                      <Trash2Icon className="h-3.5 w-3.5" />
                    </button>
                    {/* Resize handle */}
                    <div
                      className="absolute bottom-0 right-0 z-10 hidden h-5 w-5 cursor-se-resize items-center justify-center group-hover:flex"
                      onMouseDown={(e) => handleResizeStart(e, widget.id)}
                    >
                      <svg width="10" height="10" viewBox="0 0 10 10" className="text-muted-foreground">
                        <path d="M0 10 L10 0" stroke="currentColor" strokeWidth="1.5" />
                        <path d="M5 10 L10 5" stroke="currentColor" strokeWidth="1.5" />
                        <path d="M0 10 L10 10" stroke="transparent" />
                      </svg>
                    </div>
                  </>
                )}
              </div>
            ))}
          </div>
        )}
      </div>

      <Dialog open={addOpen} onOpenChange={setAddOpen}>
        <DialogContent>
          <DialogHeader>
            <DialogTitle>Add widget</DialogTitle>
            <DialogDescription>
              Choose a saved view and widget type to add to this dashboard.
            </DialogDescription>
          </DialogHeader>
          <div className="space-y-4">
            <div>
              <label className="text-sm font-medium">Widget title</label>
              <input
                value={addTitle}
                onChange={(e) => setAddTitle(e.target.value)}
                placeholder="e.g. Open tickets"
                className="mt-1 h-9 w-full rounded-md border border-input bg-card px-3 text-sm outline-none focus:border-ring"
              />
            </div>
            <div>
              <label className="text-sm font-medium">Saved view</label>
              <select
                value={addViewId}
                onChange={(e) => {
                  setAddViewId(e.target.value);
                  const view = views.find((v) => v.id === e.target.value);
                  if (view && !addTitle) setAddTitle(view.name);
                }}
                className="mt-1 h-9 w-full rounded-md border border-input bg-card px-3 text-sm outline-none focus:border-ring"
              >
                <option value="">Select a view...</option>
                {views.map((v) => (
                  <option key={v.id} value={v.id}>
                    {v.name}
                  </option>
                ))}
              </select>
            </div>
            <div>
              <label className="text-sm font-medium">Widget type</label>
              <select
                value={addType}
                onChange={(e) => setAddType(e.target.value)}
                className="mt-1 h-9 w-full rounded-md border border-input bg-card px-3 text-sm outline-none focus:border-ring"
              >
                <option value="count">Count (big number)</option>
                <option value="ticket_list">Ticket list (mini table)</option>
                <option value="status_chart">Status chart (donut)</option>
                <option value="grouped_counts">Grouped counts (bar chart)</option>
              </select>
            </div>
            {addType === "grouped_counts" && (
              <div>
                <label className="text-sm font-medium">Group by</label>
                <select
                  value={addGroupBy}
                  onChange={(e) => setAddGroupBy(e.target.value)}
                  className="mt-1 h-9 w-full rounded-md border border-input bg-card px-3 text-sm outline-none focus:border-ring"
                >
                  <option value="owner">Owner</option>
                  <option value="queue">Queue</option>
                </select>
              </div>
            )}
          </div>
          <DialogFooter>
            <Button variant="outline" size="sm" onClick={() => setAddOpen(false)}>
              Cancel
            </Button>
            <Button
              size="sm"
              disabled={!addViewId || !addTitle.trim() || adding}
              onClick={handleAddWidget}
            >
              {adding ? "Adding..." : "Add widget"}
            </Button>
          </DialogFooter>
        </DialogContent>
      </Dialog>
    </div>
  );
}
