import { useEffect, useMemo, useState } from "react";

export const DEFAULT_PHONE_MAX = 768;
export const DEFAULT_TABLET_MAX = 1024;

type DeviceType = "phone" | "tablet" | "desktop";

type DeviceInfo = {
  isMobile: boolean;
  deviceType: DeviceType;

  // Señales útiles para decisiones finas de UX:
  widthNarrow: boolean; // <= phoneMax
  widthTablet: boolean; // > phoneMax && <= tabletMax
  pointerCoarse: boolean; // puntero táctil grueso
  hoverNone: boolean; // no hay hover
  maxTouchPoints: number;

  // Info de plataforma cuando está disponible
  platform?: string;
  model?: string;
  uaMobileHint?: boolean; // de UA/Client Hints si se puede
};

type Options = {
  phoneMax?: number; // por defecto DEFAULT_PHONE_MAX
  tabletMax?: number; // por defecto DEFAULT_TABLET_MAX

  // Para SSR/Next: primera suposición que evitará saltos visuales
  serverGuess?: Partial<Pick<DeviceInfo, "deviceType" | "isMobile">>;
};

/** Hook base para media queries */
function useMediaQuery(query: string, fallback = false) {
  const [matches, setMatches] = useState(fallback);

  useEffect(() => {
    if (typeof window === "undefined") return; // SSR
    const mql = window.matchMedia(query);
    const onChange = (e: MediaQueryListEvent) => setMatches(e.matches);
    setMatches(mql.matches);
    mql.addEventListener?.("change", onChange);
    return () => mql.removeEventListener?.("change", onChange);
  }, [query]);

  return matches;
}

/** Clasificador a partir de señales */
function classifyDevice(
  widthNarrow: boolean,
  widthTablet: boolean,
  pointerCoarse: boolean,
  hoverNone: boolean
): DeviceType {
  // Heurística práctica:
  if (pointerCoarse && (widthNarrow || hoverNone)) return "phone";
  if (pointerCoarse && widthTablet) return "tablet";
  return "desktop";
}

export function useDeviceInfo(opts: Options = {}): DeviceInfo {
  const phoneMax = opts.phoneMax ?? DEFAULT_PHONE_MAX;
  const tabletMax = opts.tabletMax ?? DEFAULT_TABLET_MAX;

  // Inicialización segura para SSR para evitar hydration mismatch.
  // Si hay serverGuess, úsalo; si no, asume desktop hasta montar.
  const [initial, setInitial] = useState<DeviceInfo | null>(() => {
    if (typeof window === "undefined") {
      const deviceType = opts.serverGuess?.deviceType ?? "desktop";
      const isMobile = opts.serverGuess?.isMobile ?? deviceType !== "desktop";
      return {
        isMobile,
        deviceType,
        widthNarrow: deviceType === "phone",
        widthTablet: deviceType === "tablet",
        pointerCoarse: deviceType !== "desktop",
        hoverNone: deviceType !== "desktop",
        maxTouchPoints: 0,
      };
    }
    return null; // en cliente, calcularemos real en useEffect
  });

  const widthNarrow = useMediaQuery(`(max-width: ${phoneMax}px)`, initial?.widthNarrow ?? false);
  const widthTablet = useMediaQuery(
    `(min-width: ${phoneMax + 1}px) and (max-width: ${tabletMax}px)`,
    initial?.widthTablet ?? false
  );
  const pointerCoarse = useMediaQuery("(pointer: coarse)", initial?.pointerCoarse ?? false);
  const hoverNone = useMediaQuery("(hover: none)", initial?.hoverNone ?? false);

  const [maxTouchPoints, setMaxTouchPoints] = useState(initial?.maxTouchPoints ?? 0);
  const [uaHints, setUaHints] = useState<{ platform?: string; model?: string; mobile?: boolean }>(
    {}
  );

  useEffect(() => {
    if (typeof window === "undefined") return;
    // maxTouchPoints es útil para detectar iPadOS que se disfraza de Mac
    setMaxTouchPoints(navigator.maxTouchPoints || 0);

    // Client Hints (Chromium). No bloquea si no existen.
    (async () => {
      const nav = navigator as any;
      if (nav.userAgentData?.getHighEntropyValues) {
        try {
          const { platform, mobile, model } = await nav.userAgentData.getHighEntropyValues([
            "platform",
            "mobile",
            "model",
          ]);
          setUaHints({ platform, mobile, model });
        } catch {
          // ignorar excepciones
        }
      }
    })();
  }, []);

  const deviceType = useMemo(() => {
    // Si es Mac pero con touchPoints > 1 => probablemente iPadOS en modo desktop
    const forceTouch =
      typeof window !== "undefined" &&
      /Macintosh/i.test(navigator.userAgent || "") &&
      maxTouchPoints > 1;

    return classifyDevice(
      widthNarrow,
      widthTablet,
      pointerCoarse || forceTouch,
      hoverNone || forceTouch
    );
  }, [widthNarrow, widthTablet, pointerCoarse, hoverNone, maxTouchPoints]);

  const isMobile = deviceType !== "desktop";

  // Si teníamos estado inicial en SSR, al primer render en cliente lo reemplazamos por el real
  useEffect(() => {
    if (initial) setInitial(null);
  }, [initial]);

  return {
    isMobile,
    deviceType,
    widthNarrow,
    widthTablet,
    pointerCoarse,
    hoverNone,
    maxTouchPoints,
    platform: uaHints.platform,
    model: uaHints.model,
    uaMobileHint: uaHints.mobile,
  };
}
