"use client";

import { useGetAbout } from "@/app/[name]/(Main)/about/hooks/useAboutData";
import {
  applyCustomImageCssVariables,
  applyPatternCssVariables,
  clearCustomImageCssVariables,
  clearPatternCssVariables,
  colorizeSvg,
  hexToRgba,
  isCustomImageBackground,
  isPatternBackground,
  normalizeBgNumber,
  PATTERN_BACKGROUND_OPACITY,
} from "@/lib/helpers/backgroundUtils";
import {
  applyCachedThemeToDom,
  buildThemeCacheFromRestaurant,
  getThemeCache,
  removeCachedThemeBackground,
  setThemeCache,
  svgToDataUrl,
  themeBackgroundMatches,
  type CachedRestaurantTheme,
} from "@/lib/helpers/themeCache";
import { useParams } from "next/navigation";
import {
  createContext,
  useContext,
  useEffect,
  useLayoutEffect,
  useMemo,
  useState,
  type CSSProperties,
  type ReactNode,
} from "react";

const DEFAULT_MENU_COLOR = "#1E3A8A";

export type CustomImageSettings = {
  bgUrl: string;
  bgBlur: number | null;
  bgOpacity: number | null;
  bgOverlay: string | null;
};

type PatternBackgroundContextValue = {
  isPattern: boolean;
  isCustomImage: boolean;
  backgroundStyle: CSSProperties;
  customImageSettings: CustomImageSettings | null;
};

const PatternBackgroundContext = createContext<PatternBackgroundContextValue>({
  isPattern: false,
  isCustomImage: false,
  backgroundStyle: {},
  customImageSettings: null,
});

export function PatternBackgroundProvider({ children }: { children: ReactNode }) {
  const { name: restaurantSlug } = useParams<{ name: string }>();
  const { data: aboutData } = useGetAbout();
  const restaurant = aboutData?.data;
  const [hydratedCache, setHydratedCache] = useState<CachedRestaurantTheme | null>(null);
  const [patternImageUrl, setPatternImageUrl] = useState<string | null>(null);

  const isPattern = restaurant
    ? isPatternBackground(restaurant)
    : (hydratedCache?.isPattern ?? false);

  const isCustomImage = restaurant
    ? isCustomImageBackground(restaurant)
    : (!hydratedCache?.isPattern && !!hydratedCache?.bgUrl);
  const menuColor =
    restaurant?.menuColor || hydratedCache?.menuColor || DEFAULT_MENU_COLOR;
  const baseTint = hexToRgba(menuColor, PATTERN_BACKGROUND_OPACITY);

  useLayoutEffect(() => {
    if (!restaurantSlug) return;

    const cached = getThemeCache(restaurantSlug);
    setHydratedCache(cached);

    if (!cached) return;

    applyCachedThemeToDom(cached);
    if (cached.patternDataUrl) {
      setPatternImageUrl(cached.patternDataUrl);
    }
  }, [restaurantSlug]);

  useEffect(() => {
    if (!restaurantSlug) {
      clearPatternCssVariables();
      removeCachedThemeBackground();
      setPatternImageUrl(null);
      return;
    }

    if (!restaurant) return;

    const themeBase = buildThemeCacheFromRestaurant(restaurant);

    if (!themeBase.isPattern) {
      clearPatternCssVariables();
      setPatternImageUrl(null);

      if (isCustomImageBackground(restaurant)) {
        applyCustomImageCssVariables();
        setThemeCache(restaurantSlug, { ...themeBase, patternDataUrl: null });
      } else {
        clearCustomImageCssVariables();
        removeCachedThemeBackground();
        setThemeCache(restaurantSlug, { ...themeBase, patternDataUrl: null });
      }
      return;
    }

    clearCustomImageCssVariables();

    applyPatternCssVariables(menuColor);

    if (!themeBase.bgUrl) {
      setPatternImageUrl(null);
      setThemeCache(restaurantSlug, {
        ...themeBase,
        patternDataUrl: null,
      });
      const saved = getThemeCache(restaurantSlug);
      if (saved) {
        applyCachedThemeToDom(saved);
      }
      return;
    }

    const cached = getThemeCache(restaurantSlug);
    const cacheHit =
      cached &&
      themeBackgroundMatches(cached, restaurant) &&
      cached.isPattern &&
      cached.patternDataUrl;

    if (cacheHit) {
      setPatternImageUrl(cached.patternDataUrl!);
      setThemeCache(restaurantSlug, {
        ...themeBase,
        patternDataUrl: cached.patternDataUrl,
      });
      applyCachedThemeToDom(cached);
      return;
    }

    let cancelled = false;
    const proxyUrl = `/${restaurantSlug}/api/proxy-svg?url=${encodeURIComponent(themeBase.bgUrl)}`;

    fetch(proxyUrl)
      .then((response) => {
        if (!response.ok) {
          throw new Error("Failed to fetch background pattern");
        }
        return response.text();
      })
      .then((svg) => {
        if (cancelled) return;

        const dataUrl = svgToDataUrl(colorizeSvg(svg, menuColor));
        setPatternImageUrl(dataUrl);

        const nextCache = {
          ...themeBase,
          patternDataUrl: dataUrl,
        };
        setThemeCache(restaurantSlug, nextCache);

        const saved = getThemeCache(restaurantSlug);
        if (saved) {
          applyCachedThemeToDom(saved);
        }
      })
      .catch(() => {
        if (!cancelled && cached?.patternDataUrl) {
          setPatternImageUrl(cached.patternDataUrl);
          applyCachedThemeToDom(cached);
        }
      });

    return () => {
      cancelled = true;
    };
  }, [menuColor, restaurant, restaurantSlug]);

  const backgroundStyle = useMemo<CSSProperties>(
    () => ({
      backgroundColor: baseTint,
      ...(patternImageUrl
        ? {
            backgroundImage: `url("${patternImageUrl}")`,
            backgroundRepeat: "repeat",
            backgroundSize: "auto",
          }
        : {}),
    }),
    [baseTint, patternImageUrl],
  );

  const customImageSettings = useMemo<CustomImageSettings | null>(() => {
    const src = restaurant?.bgUrl || hydratedCache?.bgUrl;
    if (!isCustomImage || !src) return null;
    return {
      bgUrl: src,
      bgBlur: normalizeBgNumber(restaurant?.bgBlur ?? hydratedCache?.bgBlur),
      bgOpacity: normalizeBgNumber(restaurant?.bgOpacity ?? hydratedCache?.bgOpacity),
      bgOverlay: restaurant?.bgOverlay ?? hydratedCache?.bgOverlay ?? null,
    };
  }, [isCustomImage, restaurant, hydratedCache]);

  const value = useMemo(
    () => ({ isPattern, isCustomImage, backgroundStyle, customImageSettings }),
    [backgroundStyle, isPattern, isCustomImage, customImageSettings],
  );

  return (
    <PatternBackgroundContext.Provider value={value}>
      {children}
    </PatternBackgroundContext.Provider>
  );
}

export function usePatternBackground() {
  return useContext(PatternBackgroundContext);
}
