import { useState, useEffect, useMemo, useRef } from "react";
import { useTranslation } from "react-i18next";
import { useLocation } from "wouter";
import {
  useListApps,
  getListAppsQueryKey,
  useGetHomeStats,
  getGetHomeStatsQueryKey,
  useListNotifications,
  getListNotificationsQueryKey,
  useLogout,
  useUpdateLanguage,
  useUpdateMyAppOrder,
  logAppOpen,
  getGetMeQueryKey,
  type App,
} from "@workspace/api-client-react";
import { useQueryClient } from "@tanstack/react-query";
import { useAuth } from "@/contexts/AuthContext";
import {
  Bell,
  Inbox,
  LogOut,
  Globe,
  Grid2X2,
  Coffee,
  MessageSquare,
  BellRing,
  Sparkles,
} from "lucide-react";
import * as LucideIcons from "lucide-react";
import type { LucideIcon } from "lucide-react";
import i18n from "@/i18n";
import {
  DndContext,
  PointerSensor,
  TouchSensor,
  useSensor,
  useSensors,
  closestCenter,
  type DragEndEvent,
} from "@dnd-kit/core";
import {
  SortableContext,
  arrayMove,
  rectSortingStrategy,
  useSortable,
} from "@dnd-kit/sortable";
import { CSS } from "@dnd-kit/utilities";
import {
  formatDate,
  formatTime,
  formatNumber,
} from "@/lib/i18n-format";
import {
  Clock,
  useNow,
  AnalogClockWidget,
  useHomeClockVisibility,
  useTopbarClockVisibility,
  useHomeClockSize,
  useHomeClockPosition,
  type HomeClockSize,
} from "@/components/clock";
import { ClockStylePicker } from "@/components/clock-style-picker";

type IconName = keyof typeof LucideIcons;
function isIconName(x: string): x is IconName {
  return x in LucideIcons;
}
function resolveIcon(name: string): LucideIcon {
  if (isIconName(name)) {
    const Candidate = LucideIcons[name] as unknown;
    if (typeof Candidate === "function" || typeof Candidate === "object") {
      return Candidate as LucideIcon;
    }
  }
  return LucideIcons.Grid2X2;
}

function gradientForColor(color: string): string {
  const c = (color ?? "").toLowerCase();
  if (c.includes("a855f7") || c.includes("8b5cf6") || c.includes("purple") || c.includes("violet")) return "icon-tile-purple";
  if (c.includes("10b981") || c.includes("22c55e") || c.includes("green") || c.includes("emerald")) return "icon-tile-green";
  if (c.includes("f59e0b") || c.includes("f97316") || c.includes("orange") || c.includes("amber")) return "icon-tile-orange";
  if (c.includes("ec4899") || c.includes("pink") || c.includes("rose")) return "icon-tile-pink";
  if (c.includes("14b8a6") || c.includes("06b6d4") || c.includes("teal") || c.includes("cyan")) return "icon-tile-teal";
  return "icon-tile-blue";
}

function AppIconContent({ app }: { app: { nameAr: string; nameEn: string; iconName: string; color: string } }) {
  const { i18n: i18nInstance } = useTranslation();
  const lang = i18nInstance.language;
  const name = lang === "ar" ? app.nameAr : app.nameEn;

  const Icon = resolveIcon(app.iconName);

  return (
    <>
      <div className={`icon-tile w-[68px] h-[68px] sm:w-[72px] sm:h-[72px] ${gradientForColor(app.color)} group-hover:scale-105 group-active:scale-95`}>
        <Icon size={30} color="#FFFFFF" />
      </div>
      <span className="text-[11px] text-foreground/85 font-medium text-center leading-tight max-w-[78px] truncate">
        {name}
      </span>
    </>
  );
}

function SortableAppIcon({ app, onClick }: { app: App; onClick: () => void }) {
  const { attributes, listeners, setNodeRef, transform, transition, isDragging } = useSortable({ id: `app-${app.id}` });
  const style: React.CSSProperties = {
    transform: CSS.Transform.toString(transform),
    transition,
    opacity: isDragging ? 0.6 : 1,
    zIndex: isDragging ? 20 : "auto",
    touchAction: "none",
  };
  return (
    <button
      type="button"
      ref={setNodeRef}
      style={style}
      onClick={onClick}
      className="flex flex-col items-center gap-2 group"
      {...attributes}
      {...listeners}
    >
      <AppIconContent app={app} />
    </button>
  );
}

const CLOCK_TILE_ID = "__clock";

function useGridCols(): number {
  const compute = () => {
    if (typeof window === "undefined") return 8;
    const w = window.innerWidth;
    if (w >= 1024) return 8;
    if (w >= 768) return 7;
    if (w >= 640) return 6;
    return 4;
  };
  const [cols, setCols] = useState<number>(compute);
  useEffect(() => {
    const onResize = () => setCols(compute());
    window.addEventListener("resize", onResize);
    return () => window.removeEventListener("resize", onResize);
  }, []);
  return cols;
}

function SortableClockTile({
  time,
  lang,
  hour12,
  size,
  onToggleSize,
  pinColumn,
}: {
  time: Date;
  lang: string;
  hour12: boolean | null | undefined;
  size: HomeClockSize;
  onToggleSize: () => void;
  pinColumn?: number;
}) {
  const { attributes, listeners, setNodeRef, transform, transition, isDragging } = useSortable({
    id: CLOCK_TILE_ID,
  });
  const isLarge = size === "large";
  const px = isLarge ? 168 : 78;
  const effectivePinColumn =
    pinColumn && isLarge ? Math.max(pinColumn - 1, 1) : pinColumn;
  const style: React.CSSProperties = {
    transform: CSS.Transform.toString(transform),
    transition,
    opacity: isDragging ? 0.6 : 1,
    zIndex: isDragging ? 20 : "auto",
    touchAction: "none",
    ...(effectivePinColumn && !isDragging
      ? { gridColumnStart: effectivePinColumn, gridRowStart: 1 }
      : {}),
  };

  const longPressTimer = useRef<number | null>(null);
  const startPos = useRef<{ x: number; y: number } | null>(null);

  const clearTimer = () => {
    if (longPressTimer.current !== null) {
      window.clearTimeout(longPressTimer.current);
      longPressTimer.current = null;
    }
  };

  useEffect(() => {
    if (isDragging) clearTimer();
  }, [isDragging]);

  const dndPointerDown = listeners?.onPointerDown as
    | ((e: React.PointerEvent) => void)
    | undefined;

  const onPointerDown = (e: React.PointerEvent) => {
    startPos.current = { x: e.clientX, y: e.clientY };
    clearTimer();
    longPressTimer.current = window.setTimeout(() => {
      onToggleSize();
    }, 500);
    dndPointerDown?.(e);
  };
  const onPointerMove = (e: React.PointerEvent) => {
    if (!startPos.current) return;
    const dx = e.clientX - startPos.current.x;
    const dy = e.clientY - startPos.current.y;
    if (dx * dx + dy * dy > 64) clearTimer();
  };
  const onPointerUp = () => {
    clearTimer();
    startPos.current = null;
  };

  const { onPointerDown: _ignored, ...restListeners } = listeners ?? {};

  return (
    <div
      ref={setNodeRef}
      style={style}
      className={`flex flex-col items-center gap-2 group select-none ${isLarge ? "col-span-2 row-span-2" : ""}`}
      {...attributes}
      {...restListeners}
      onPointerDown={onPointerDown}
      onPointerMove={onPointerMove}
      onPointerUp={onPointerUp}
      onPointerCancel={onPointerUp}
    >
      <div
        className={`relative flex items-center justify-center text-foreground group-hover:scale-105 group-active:scale-95 transition-transform ${
          isLarge ? "w-[168px] h-[168px]" : "w-[78px] h-[78px]"
        }`}
        aria-label="Clock"
      >
        <AnalogClockWidget
          time={time}
          lang={lang}
          hour12={hour12}
          size={px - (isLarge ? 16 : 10)}
          showLabels={false}
        />
      </div>
      <span className="text-[11px] text-foreground/85 font-medium text-center leading-tight max-w-[78px] truncate">
        {formatTime(time, lang, {
          hour: "2-digit",
          minute: "2-digit",
          hour12: resolveClockHour12Bool(hour12),
        })}
      </span>
    </div>
  );
}

function resolveClockHour12Bool(v: boolean | null | undefined): boolean {
  return v ?? false;
}

type StatCardProps = {
  label: string;
  value: string;
  Icon: typeof Grid2X2;
  iconClass: string;
};

function StatCard({ label, value, Icon, iconClass }: StatCardProps) {
  return (
    <div className="glass-panel rounded-2xl p-3 flex items-center gap-3">
      <div className={`shrink-0 w-10 h-10 rounded-xl flex items-center justify-center ${iconClass}`}>
        <Icon size={18} />
      </div>
      <div className="min-w-0">
        <div className="text-xl font-bold text-foreground leading-none tabular-nums">{value}</div>
        <div className="text-[11px] text-muted-foreground mt-1 truncate">{label}</div>
      </div>
    </div>
  );
}

export default function HomePage() {
  const { t, i18n: i18nInstance } = useTranslation();
  const [, setLocation] = useLocation();
  const { user } = useAuth();
  const queryClient = useQueryClient();
  const time = useNow();
  const lang = i18nInstance.language;

  const { data: apps } = useListApps({ query: { queryKey: getListAppsQueryKey() } });
  const updateOrder = useUpdateMyAppOrder();
  const [orderedApps, setOrderedApps] = useState<App[] | null>(null);

  useEffect(() => {
    if (!apps) return;
    const activeApps = apps.filter((a) => a.isActive);
    setOrderedApps((prev) => {
      if (!prev) return activeApps;
      const byId = new Map(activeApps.map((a) => [a.id, a]));
      const kept = prev
        .map((a) => byId.get(a.id))
        .filter((a): a is App => a !== undefined);
      const keptIds = new Set(kept.map((a) => a.id));
      const added = activeApps.filter((a) => !keptIds.has(a.id));
      return [...kept, ...added];
    });
  }, [apps]);

  const sensors = useSensors(
    useSensor(PointerSensor, { activationConstraint: { distance: 8 } }),
    useSensor(TouchSensor, { activationConstraint: { delay: 250, tolerance: 5 } }),
  );

  const gridCols = useGridCols();
  const [homeClockVisible, setHomeClockVisible] = useHomeClockVisibility();
  const [topbarClockVisible] = useTopbarClockVisibility();
  const [clockSize, setClockSize] = useHomeClockSize(user?.id);
  const [clockPos, setClockPos] = useHomeClockPosition(user?.id);
  const toggleClockSize = () => setClockSize(clockSize === "large" ? "compact" : "large");

  const appCount = (orderedApps ?? []).length;
  const isClockUnset = clockPos < 0;
  // Only meaningful in RTL: when the user drags the clock past the last
  // app, treat it as "pin to the absolute far-left cell" so they can
  // reach that cell even when there are fewer apps than columns.
  // In LTR the far-right is already reachable naturally so we don't
  // hijack the saved index there.
  const isRtlClockAtEnd = lang === "ar" && clockPos >= appCount;
  const shouldPinFarLeft = (isClockUnset || isRtlClockAtEnd) && lang === "ar" && homeClockVisible;
  const combinedIds = useMemo(() => {
    const appIds = (orderedApps ?? []).map((a) => `app-${a.id}`);
    if (!homeClockVisible) return appIds;
    if (isClockUnset) {
      // Default placement: LTR -> front of array (visually leftmost);
      // RTL -> appended to end and CSS-pinned to the last column of row 1.
      return lang === "ar" ? [...appIds, CLOCK_TILE_ID] : [CLOCK_TILE_ID, ...appIds];
    }
    if (isRtlClockAtEnd) {
      // RTL only: user dragged clock to / past the end -> pin far-left.
      return [...appIds, CLOCK_TILE_ID];
    }
    const safePos = Math.min(Math.max(clockPos, 0), appIds.length);
    const out: string[] = [...appIds];
    out.splice(safePos, 0, CLOCK_TILE_ID);
    return out;
  }, [orderedApps, clockPos, homeClockVisible, lang, isClockUnset, isRtlClockAtEnd]);
  const clockPinColumn = shouldPinFarLeft ? Math.max(gridCols, 1) : undefined;
  const sortableIds = combinedIds;

  const handleDragEnd = (event: DragEndEvent) => {
    const { active, over } = event;
    if (!over || active.id === over.id || !orderedApps) return;
    const oldIndex = combinedIds.findIndex((id) => id === active.id);
    const newIndex = combinedIds.findIndex((id) => id === over.id);
    if (oldIndex < 0 || newIndex < 0) return;
    const nextCombined = arrayMove(combinedIds, oldIndex, newIndex);
    const newClockPos = nextCombined.findIndex((id) => id === CLOCK_TILE_ID);
    if (newClockPos >= 0 && newClockPos !== clockPos) setClockPos(newClockPos);
    const newAppOrder = nextCombined
      .filter((id) => id !== CLOCK_TILE_ID)
      .map((id) => Number(String(id).slice(4)))
      .map((id) => orderedApps.find((a) => a.id === id))
      .filter((a): a is App => a !== undefined);
    const sameAppOrder =
      newAppOrder.length === orderedApps.length &&
      newAppOrder.every((a, i) => a.id === orderedApps[i].id);
    if (sameAppOrder) return;
    const previous = orderedApps;
    setOrderedApps(newAppOrder);
    updateOrder.mutate(
      { data: { order: newAppOrder.map((a) => a.id) } },
      {
        onSuccess: (data) => {
          setOrderedApps(data);
          queryClient.setQueryData(getListAppsQueryKey(), data);
        },
        onError: () => {
          setOrderedApps(previous);
          queryClient.invalidateQueries({ queryKey: getListAppsQueryKey() });
        },
      },
    );
  };

  const { data: stats } = useGetHomeStats({ query: { queryKey: getGetHomeStatsQueryKey() } });
  const { data: notifications } = useListNotifications({ query: { queryKey: getListNotificationsQueryKey() } });

  const logout = useLogout();
  const updateLanguage = useUpdateLanguage();

  const openApp = (app: App) => {
    // Fire-and-forget: keepalive ensures the request survives any
    // imminent navigation triggered by setLocation below.
    logAppOpen(app.id, { keepalive: true }).catch(() => {
      // Best-effort tracking; ignore failures so navigation isn't blocked.
    });
    setLocation(app.route);
  };

  const unreadCount = notifications?.filter((n) => !n.isRead).length ?? stats?.unreadNotifications ?? 0;

  const displayName = lang === "ar"
    ? (user?.displayNameAr ?? user?.username ?? "")
    : (user?.displayNameEn ?? user?.username ?? "");

  const isAdmin = user?.roles?.includes("admin") ?? false;
  const canReceiveOrders =
    isAdmin || (user?.roles?.includes("order_receiver") ?? false);

  const handleLogout = () => {
    logout.mutate(undefined, {
      onSuccess: () => {
        queryClient.clear();
        setLocation("/login");
      },
    });
  };

  const toggleLanguage = () => {
    const newLang = lang === "ar" ? "en" : "ar";
    i18n.changeLanguage(newLang);
    updateLanguage.mutate(
      { data: { language: newLang } },
      { onSuccess: () => queryClient.invalidateQueries({ queryKey: getGetMeQueryKey() }) },
    );
  };

  const dockApps = (orderedApps ?? apps)?.filter((a) => ["services", "chat", "notifications", "admin"].includes(a.slug)) ?? [];

  const initials = (displayName || "?").trim().slice(0, 1).toUpperCase();

  return (
    <div className="min-h-screen os-bg flex flex-col overflow-hidden relative">
      {/*
        Status Bar
        --------------------------------------------------------------
        Sizing scales by device class so the bar feels natural at each
        size — phones stay compact (the original design), iPad gets a
        noticeably taller bar with bigger tap targets so it doesn't
        look lost on a larger screen, and desktop matches iPad. We
        switch at the `md:` breakpoint (≥768px), which is the standard
        iPad-portrait threshold; mobile (<768px) renders identically
        to before this change.
      */}
      <div className="topbar-glass px-4 sm:px-6 md:px-8 py-3 md:py-4 flex items-center justify-between gap-3 md:gap-5 z-10 sticky top-0">
        {/* Identity */}
        <div className="flex items-center gap-2.5 md:gap-3.5 min-w-0 shrink basis-0 flex-1">
          <div className="w-9 h-9 md:w-12 md:h-12 rounded-full bg-primary/15 text-primary flex items-center justify-center font-bold text-sm md:text-lg shrink-0">
            {initials}
          </div>
          <div className="min-w-0 hidden sm:block">
            <div className="text-foreground font-semibold text-sm md:text-base truncate leading-tight">{displayName}</div>
            {isAdmin && (
              <div className="text-[10px] md:text-xs text-muted-foreground leading-tight">Admin</div>
            )}
          </div>
        </div>

        {/* Clock + dates */}
        {topbarClockVisible && (
          <div className="px-2 md:px-3 shrink-0">
            <Clock
              style={user?.clockStyle ?? null}
              hour12={user?.clockHour12 ?? null}
              time={time}
              lang={lang}
            />
          </div>
        )}

        {/*
          Controls — buttons grow on iPad+ via padding + icon size.
          Lucide icons size via `width`/`height` SVG attrs; we drop the
          numeric `size` prop and use Tailwind classes so the icon
          itself can scale at the `md:` breakpoint.
        */}
        <div className="flex items-center gap-1 md:gap-2 shrink basis-0 flex-1 justify-end">
          <ClockStylePicker
            currentStyle={user?.clockStyle ?? null}
            currentHour12={user?.clockHour12 ?? null}
          />
          <button
            onClick={toggleLanguage}
            aria-label="Toggle language"
            className="text-muted-foreground hover:text-foreground transition-colors p-1.5 md:p-2.5 rounded-lg md:rounded-xl hover:bg-foreground/5"
          >
            <Globe className="w-[18px] h-[18px] md:w-6 md:h-6" />
          </button>
          {canReceiveOrders && (
            <button
              onClick={() => setLocation("/orders/incoming")}
              aria-label={t("incomingOrders.linkLabel")}
              className="p-1.5 md:p-2.5 rounded-lg md:rounded-xl hover:bg-foreground/5 text-muted-foreground hover:text-foreground transition-colors"
            >
              <Inbox className="w-[18px] h-[18px] md:w-6 md:h-6" />
            </button>
          )}
          <button
            onClick={() => setLocation("/notifications")}
            className="relative p-1.5 md:p-2.5 rounded-lg md:rounded-xl hover:bg-foreground/5 text-muted-foreground hover:text-foreground transition-colors"
          >
            <Bell className="w-[18px] h-[18px] md:w-6 md:h-6" />
            {unreadCount > 0 && (
              <span className="absolute -top-0.5 -right-0.5 bg-destructive text-destructive-foreground text-[10px] md:text-xs rounded-full min-w-[16px] md:min-w-[20px] h-4 md:h-5 px-1 flex items-center justify-center font-bold tabular-nums">
                {unreadCount > 9 ? "9+" : unreadCount}
              </span>
            )}
          </button>
          <button
            onClick={handleLogout}
            className="p-1.5 md:p-2.5 rounded-lg md:rounded-xl hover:bg-foreground/5 text-muted-foreground hover:text-foreground transition-colors"
          >
            <LogOut className="w-[18px] h-[18px] md:w-6 md:h-6" />
          </button>
        </div>
      </div>

      {/* Main Content */}
      <div className="flex-1 px-5 sm:px-8 pt-6 pb-32 overflow-y-auto">
        {/* Stats Row — admin only */}
        {isAdmin && stats && (
          <div className="grid grid-cols-2 sm:grid-cols-4 gap-3 mb-8 max-w-4xl">
            <StatCard
              label={t("home.stats.apps")}
              value={formatNumber(stats.totalApps, lang)}
              Icon={Grid2X2}
              iconClass="bg-primary/15 text-primary"
            />
            <StatCard
              label={t("home.stats.services")}
              value={formatNumber(stats.totalServices, lang)}
              Icon={Coffee}
              iconClass="bg-amber-100 text-amber-600"
            />
            <StatCard
              label={t("home.stats.messages")}
              value={formatNumber(stats.unreadMessages, lang)}
              Icon={MessageSquare}
              iconClass="bg-emerald-100 text-emerald-600"
            />
            <StatCard
              label={t("home.stats.alerts")}
              value={formatNumber(stats.unreadNotifications, lang)}
              Icon={BellRing}
              iconClass="bg-rose-100 text-rose-600"
            />
          </div>
        )}

        {/* Apps Grid */}
        <div className="mb-4">
          {orderedApps && orderedApps.length === 0 ? (
            <div className="glass-panel rounded-2xl p-8 text-center max-w-md mx-auto">
              <div className="mx-auto w-12 h-12 rounded-2xl bg-primary/10 text-primary flex items-center justify-center mb-3">
                <Sparkles size={22} />
              </div>
              <div className="font-semibold text-foreground">{t("home.noApps")}</div>
              <div className="text-sm text-muted-foreground mt-1">{t("home.noAppsHint")}</div>
            </div>
          ) : (
            <DndContext sensors={sensors} collisionDetection={closestCenter} onDragEnd={handleDragEnd}>
              <SortableContext items={sortableIds} strategy={rectSortingStrategy}>
                <div className="grid grid-cols-4 sm:grid-cols-6 md:grid-cols-7 lg:grid-cols-8 gap-x-3 gap-y-5 grid-flow-row-dense">
                  {combinedIds.map((id) => {
                    if (id === CLOCK_TILE_ID) {
                      if (!homeClockVisible) return null;
                      return (
                        <SortableClockTile
                          key={CLOCK_TILE_ID}
                          time={time}
                          lang={lang}
                          hour12={user?.clockHour12 ?? null}
                          size={clockSize}
                          onToggleSize={toggleClockSize}
                          pinColumn={clockPinColumn}
                        />
                      );
                    }
                    const appId = Number(String(id).slice(4));
                    const app = orderedApps?.find((a) => a.id === appId);
                    if (!app) return null;
                    return (
                      <SortableAppIcon
                        key={app.id}
                        app={app}
                        onClick={() => openApp(app)}
                      />
                    );
                  })}
                </div>
              </SortableContext>
            </DndContext>
          )}
        </div>
      </div>

      {/* Bottom Dock */}
      <div className="fixed bottom-0 left-0 right-0 p-4 z-10 pointer-events-none">
        <div className="dock-glass rounded-3xl px-6 py-3 flex items-center justify-around max-w-sm mx-auto pointer-events-auto">
          {dockApps.slice(0, 4).map((app) => {
            const Icon = resolveIcon(app.iconName);
            const showBadge = app.slug === "notifications" && unreadCount > 0;
            return (
              <button
                key={app.id}
                onClick={() => openApp(app)}
                className="relative flex flex-col items-center gap-1 group"
              >
                <div
                  className="w-12 h-12 rounded-xl flex items-center justify-center group-hover:scale-110 transition-transform"
                  style={{ backgroundColor: `${app.color}25` }}
                >
                  <Icon size={22} color={app.color} />
                </div>
                {showBadge && (
                  <span className="absolute -top-1 -right-1 bg-destructive text-destructive-foreground text-[10px] rounded-full min-w-[16px] h-4 px-1 flex items-center justify-center font-bold tabular-nums">
                    {unreadCount > 9 ? "9+" : unreadCount}
                  </span>
                )}
              </button>
            );
          })}
        </div>
      </div>
    </div>
  );
}
