"use client";

import { createContext, useContext, ReactNode, useState, useEffect, useRef } from "react";
import { useRouter } from "next/navigation";
import { destroyCookie, parseCookies, setCookie } from "nookies";
import { COOKIES_USER_ACCESS_TOKEN } from "./actionTypes";
import toast from "react-hot-toast";
import apis from "@/utils/apis";
import { AuthInterface } from "./interfaces";
import { getFirebaseMessageToken, onMessageListener } from "@/utils/firebase";
import { isSupported } from "firebase/messaging";
import dayjs from "dayjs";
import { toast as sonnerToast } from 'sonner';
import useFCM from "@/utils/useFCM";
import { Bell } from "lucide-react";
import { useDispatch } from "react-redux";
import { cartReset, updateAddress } from "@/store/actions/user/userAction";
import { AppDispatch } from "@/store/store";

type ToastFunction = (msg: any) => void;

interface GlobalContextType {
  setUserInfo: React.Dispatch<React.SetStateAction<any | null>>;
  setOrderInfo: React.Dispatch<React.SetStateAction<any | null>>;
  userInfo: AuthInterface | null;
  orderInfo: any | null;
  stopSpaceEnter: (event: React.KeyboardEvent) => boolean;
  logout: () => void;
  deleteAccount: () => void
  Toast: {
    error: ToastFunction;
    success: ToastFunction;
  };
  requestNotification: any,
  setNotificationData: any,
  notificationData: any,
  loginWithSocial: any,
  downloadCSV: any,
  setExportLoading: any,
  exportLoading: any,
  getProfile: any
  getCategory: any
  categoryList: any
  setCategoryList: any
  setLocationData: any
  locationData: any
  loacte: any
}

export const GlobalContext = createContext<GlobalContextType | undefined>(undefined);

interface GlobalProviderProps {
  children: ReactNode;
  userInfo?: AuthInterface;
}

function GlobalProvider({ children, userInfo: initialUserInfo }: GlobalProviderProps) {
  const router = useRouter();
  const [userInfo, setUserInfo] = useState<AuthInterface | null>(initialUserInfo || null);

  useEffect(() => {
    setUserInfo(initialUserInfo || null);
  }, [initialUserInfo]);

  const [categoryList, setCategoryList] = useState<any>([])
  const [loacte, setLoacte] = useState<any>({ lat: null, lng: null })
  const [orderInfo, setOrderInfo] = useState<any | null>(null);
  const [notificationData, setNotificationData] = useState<any | null>(null);
  const [exportLoading, setExportLoading] = useState(false)
  const [locationData, setLocationData] = useState<any>(null)
  const cookiesObj = parseCookies();
  const access_token =
    cookiesObj[COOKIES_USER_ACCESS_TOKEN] ||
    cookiesObj["cookies_user_access_token"] ||
    (typeof window !== "undefined"
      ? sessionStorage.getItem("token") || localStorage.getItem("auth_token")
      : null);

  const shownNotificationsRef = useRef<Map<string, number>>(new Map());

  const {
    messages: pushMessages,
    setMessages: setPushMessages,
  } = useFCM(userInfo?.access_token || "");
  if (userInfo?.access_token) {
    apis.setToken(userInfo?.access_token || "");
  }

  useEffect(() => {
    if (pushMessages) {
      const notificationTitle = pushMessages?.notification?.title || 'New Notification';
      const notificationBody = pushMessages?.notification?.body || '';
      const notificationType = pushMessages?.data?.type || '';

      console.log("🔔 [Provider] FCM foreground message received:", {
        title: notificationTitle,
        body: notificationBody,
        type: notificationType,
        messageId: (pushMessages as any)?.messageId || 'unknown'
      });

      // Deduplicate identical notifications (same title and body) within 5 seconds
      const notificationKey = `${notificationTitle}::${notificationBody}`;
      const now = Date.now();
      const lastShownTime = shownNotificationsRef.current.get(notificationKey);

      if (lastShownTime && now - lastShownTime < 5000) {
        console.log("🔔 [Provider] Skipping duplicate toast (already shown within 5s):", notificationTitle);
        setPushMessages(null);
        return;
      }

      shownNotificationsRef.current.set(notificationKey, now);
      console.log("🔔 [Provider] Triggering sonnerToast for:", notificationTitle);

      sonnerToast(notificationTitle, {
        icon: (
          <span className="w-5 h-5">
            <Bell />
          </span>
        ),
        description: notificationBody,
        duration: 5000,
        position: "top-right",
        action: notificationType === 'admin_push' ? {
          label: "View",
          onClick: () => {
            // Handle notification click action
            // console.log('Notification clicked');
          },
        } : undefined,
      });

      // Clear the message state to prevent duplicate triggers on state changes/re-renders
      setPushMessages(null);
    }
  }, [pushMessages, setPushMessages]);

  useEffect(() => {
    let handleMessage: ((event: MessageEvent) => void) | undefined;

    if (typeof window !== 'undefined' && 'serviceWorker' in navigator) {
      console.log("🔧 [Provider] Registering Service Worker /sw.js...");
      navigator.serviceWorker.register('/sw.js')
        .then((registration) => {
          console.log("🔧 [Provider] Service Worker registered successfully:", registration.scope);
        })
        .catch((error) => {
          console.error('Service Worker registration failed:', error);
        });

      handleMessage = (event: MessageEvent) => {
        console.log("📥 [Provider] Service Worker postMessage received:", event.data);
        
        // Skip Firebase messaging events here to prevent duplicate toasts in the foreground
        // (FCM foreground messages are already handled by the client SDK / useFCM hook above)
        const isFCM = 
          event.data?.isFirebaseMessaging || 
          event.data?.data?.isFirebaseMessaging || 
          event.data?.fcmMessageId || 
          event.data?.data?.fcmMessageId;

        if (isFCM) {
          console.log("📥 [Provider] Skipping SW toast because it is a Firebase message (already handled by useFCM)");
          return;
        }

        if (event.data?.messageType === 'push-received') {
          const notificationTitle = event.data?.notification?.title || 'New Notification';
          const notificationBody = event.data?.notification?.body || '';

          console.log("📥 [Provider] Showing sonnerToast from SW push-received:", notificationTitle);

          sonnerToast(notificationTitle, {
            icon: (
              <span className="w-5 h-5">
                <Bell />
              </span>
            ),
            description: notificationBody,
            duration: 3000,
            position: "top-right",
          });
        } else if (event.data?.type === 'NOTIFICATION_CLICKED') {
          const { title, body } = event.data.payload;
          console.log("📥 [Provider] Showing sonnerToast from SW NOTIFICATION_CLICKED:", title);
          sonnerToast(title, {
            icon: (
              <span className="w-5 h-5">
                <Bell />
              </span>
            ),
            description: body,
            duration: 3000,
            position: "top-right",
          });
        }
      };

      navigator.serviceWorker.addEventListener('message', handleMessage);
    }

    return () => {
      if (handleMessage && 'serviceWorker' in navigator) {
        navigator.serviceWorker.removeEventListener('message', handleMessage);
      }
    };
  }, []);

  useEffect(() => {
    let unsubscribe: (() => void) | undefined;

    const setupListener = async () => {
      try {
        const supportedBrowser = await isSupported();
        if (supportedBrowser) {
          const unsub = onMessageListener((payload) => {
            setNotificationData(payload);
          });
          if (unsub) {
            unsubscribe = unsub;
          }
        }
      } catch (error) {
        console.error("Error setting up notificationData listener:", error);
      }
    };

    if (typeof window !== "undefined" && access_token) {
      setupListener();
    }

    return () => {
      if (unsubscribe) {
        unsubscribe();
      }
    };
  }, [access_token]);

  useEffect(() => {
    const fetchUserProfile = async () => {
      const currentCookies = parseCookies();
      const currentToken =
        currentCookies[COOKIES_USER_ACCESS_TOKEN] ||
        currentCookies["cookies_user_access_token"] ||
        (typeof window !== "undefined"
          ? sessionStorage.getItem("token") || localStorage.getItem("auth_token")
          : null);

      if (currentToken && !userInfo) {
        try {
          apis.setToken(currentToken);
          const apiRes = await apis.Profile.getProfile();
          const profileData = apiRes?.data || apiRes;
          if (profileData) {
            const { appConfiguration, loyalty_wallet } = apiRes || {};
            setUserInfo({
              ...profileData,
              appConfiguration,
              loyalty_wallet,
              access_token: currentToken,
            });
          }
        } catch (error) {
          console.error("Error auto-fetching user profile in Provider:", error);
        }
      }
    };

    fetchUserProfile();

    const handleMfeAuth = (e: any) => {
      if (e.detail?.type === "MFE_AUTH_LOGIN") {
        const { token: mfeToken, user: mfeUser } = e.detail.payload || {};
        if (mfeToken) {
          apis.setToken(mfeToken);
          setUserInfo({
            ...(mfeUser || {}),
            access_token: mfeToken,
          });
        }
      } else if (e.detail?.type === "MFE_LOGOUT") {
        setUserInfo(null);
      }
    };

    if (typeof window !== "undefined") {
      window.addEventListener("READY_MFE_EVENT", handleMfeAuth);
      return () => window.removeEventListener("READY_MFE_EVENT", handleMfeAuth);
    }
  }, [access_token, userInfo]);



  const dispatch = useDispatch<AppDispatch>();
  const logout = async (): Promise<void> => {
    try {
      await apis.User.logout()
      setUserInfo(null);
      destroyCookie(null, COOKIES_USER_ACCESS_TOKEN, {
        maxAge: 0,
        path: "/",
      });
      apis.setToken("")
      dispatch(cartReset());
      dispatch(updateAddress(null));
      localStorage.clear();
      sessionStorage.clear();
      router.replace(`/home`);
    } catch (error) {
      console.error("Error during logout:", error);
      router.replace(`/home`);
      setUserInfo(null);
      destroyCookie(null, COOKIES_USER_ACCESS_TOKEN, {
        maxAge: 0,
        path: "/",
      });
      apis.setToken("")
      dispatch(cartReset());
      dispatch(updateAddress(null));
      localStorage.clear();
      sessionStorage.clear();
    }
  };


  const deleteAccount = async () => {
    try {
      const apiRes = await apis.User.delete()
      Toast.success(apiRes?.data?.message)
      setUserInfo(null);
      destroyCookie(null, COOKIES_USER_ACCESS_TOKEN, {
        maxAge: 0,
        path: "/",
      });
      apis.setToken("")

      localStorage.clear();
      sessionStorage.clear();

      const cookies = document.cookie.split(";");
      for (let i = 0; i < cookies.length; i++) {
        const cookie = cookies[i];
        const eqPos = cookie.indexOf("=");
        const name = eqPos > -1 ? cookie.substr(0, eqPos).trim() : cookie.trim();
        document.cookie = name + "=;expires=Thu, 01 Jan 1970 00:00:00 GMT;path=/";
      }

      router.replace(`/home`);
    } catch (error) {
      Toast.error(error)
    }
  }


  const convertArrayToCSV = (dataArray: any) => {
    if (dataArray.length === 0) {
      return '';
    }
    const headers = Object.keys(dataArray[0]);
    const csvRows = dataArray.map((obj: any) =>
      headers.map(header => {
        const value = obj[header] ?? '';
        const escapedValue = String(value).replace(/"/g, '""');
        return /[",\n]/.test(escapedValue) ? `"${escapedValue}"` : escapedValue;
      }).join(',')
    );

    return [headers.join(','), ...csvRows].join('\n');
  };



  const formatDate = (timestamp: number) => {
    return dayjs(timestamp).format('DD MMM, YYYY'); // Format as "06 Jan, 2025"
  };

  const filterDataByKeys = (dataArray: any, keys: any) => {
    return dataArray.map((item: any) =>
      keys.reduce((obj: any, key: any) => {
        if (key in item) {
          if (key === 'updated_at' || key === 'created_at') {
            obj[key] = formatDate(item[key]);
          } else {
            obj[key] = item[key];
          }
        }
        return obj;
      }, {})
    );
  };

  const downloadCSV = (data: any, keysToInclude: any, filename = 'data.csv') => {
    const filteredData = filterDataByKeys(data, keysToInclude);
    const csvContent = convertArrayToCSV(filteredData);
    const blob = new Blob([csvContent], { type: 'text/csv;charset=utf-8;' });
    const link = document.createElement('a');
    const url = URL.createObjectURL(blob);
    link.href = url;
    link.setAttribute('download', filename);
    document.body.appendChild(link);
    link.click();
    document.body.removeChild(link);
    URL.revokeObjectURL(url);
  };


  // social login...............................
  const loginWithSocial = async (social_type: string, social_token: string,) => {
    if (!social_token) return;
    destroyCookie(null, COOKIES_USER_ACCESS_TOKEN, {
      maxAge: 0,
      path: "/",
    });
    const timezone = Intl.DateTimeFormat().resolvedOptions().timeZone;
    if (social_token)
      try {

        // setLoading(true)
        const items = {
          social_type,
          social_token,
          timezone,
        } as any;
        const fcm_token = await requestNotification()
        if (fcm_token) {
          items["fcm_token"] = fcm_token
        }
        let apiRes = await apis.Auth.socialLogin(items);
        const data = apiRes?.data;

        const accessToken = data?.access_token;
        apis.setToken(apiRes?.data?.access_token);
        if (accessToken) {
          setCookie(null, COOKIES_USER_ACCESS_TOKEN, accessToken, {
            path: `/`,
          });
        }
        setUserInfo({
          ...apiRes?.data,
          appConfiguration: apiRes?.appConfiguration,
          loyalty_wallet: apiRes?.loyalty_wallet,
          access_token: accessToken,
        });
        router.replace("/dashboard")
      } catch (error: any) {
        Toast.error(error);
      } finally {
        // setLoading(false)
      }
  };



  const getProfile = async () => {
    try {
      const apiRes = await apis.Profile.getProfile()
      const { data, appConfiguration, loyalty_wallet } = apiRes
      setUserInfo((prev) => ({
        ...prev,
        ...data,
        appConfiguration, loyalty_wallet
      }));
      return data
    } catch (error) { }
  }


  const getCategory = async () => {
    try {
      const apiRes = await apis.category.get();
      const { data } = apiRes
      setCategoryList(data);
      return data
    } catch (error) { }
  }
  const getLocation = async () => {
    try {
      navigator.geolocation.getCurrentPosition(
        async (position) => {
          const { latitude, longitude } = position.coords;
          setLoacte({ lat: latitude, lng: longitude })
        },
        (error) => {
          console.error("Location error:", error);
        }
      );
    } catch (error) { }
  }
  useEffect(() => {
    getLocation();
    // let token:any = sessionStorage.getItem('token');
    // setUserInfo((prev) => ({
    //   ...prev, 
    //   access_token: token, 
    // }));

  }, [])


  // Prevent space or invalid key entry in inputs
  const stopSpaceEnter = (event: React.KeyboardEvent): boolean => {
    if (event.target instanceof HTMLInputElement) {
      if (event.target.value.length === 0 && event.key === " ") {
        event.preventDefault();
        return false;
      }
      if (!/^[a-zA-Z ]$/.test(event.key) && !event.ctrlKey && !event.metaKey) {
        event.preventDefault();
        return false;
      }
    }
    return true;
  };

  const requestNotification = async () => {
    if (!("Notification" in window)) {
      return "not"; // Notifications are not supported.
    }

    try {
      if (Notification.permission === "granted") {
        // If permission is already granted, fetch and return the token.
        return await getFirebaseMessageToken();
      }

      if (Notification.permission === "default") {
        // Request permission from the user.
        const permission = await Notification.requestPermission();
        if (permission === "granted") {
          return await getFirebaseMessageToken(); // Fetch and return the token.
        } else {
          return ""; // Permission denied or dismissed.
        }
      }

      // If permission is denied.
      return "";
    } catch (error) {
      console.error("Error requesting notification permission:", error);
      return ""; // Handle the error gracefully.
    }
  };


  // Success toast
  const success: ToastFunction = (message: string) => {
    toast.success(message, {
      duration: 2000,
      style: {
        fontSize: "13px",
        backgroundColor: "#fff",
      },
    });
  };


  // Error toast
  const error: ToastFunction = (err: any) => {
    const message =
      typeof err === "string"
        ? err
        : err?.response?.data?.message ||
        err?.response?.body?.message ||
        err?.message || err?.response?.body ||
        "Something went wrong";
    toast.error(message, {
      duration: 2000,
      style: {
        fontSize: "13px",
        backgroundColor: "#fff",
      },
    });
  };

  // Toast object
  const Toast = {
    success,
    error,
  };

  // Context value
  const contextValue: GlobalContextType = {
    setUserInfo,
    setOrderInfo,
    orderInfo,
    userInfo,
    stopSpaceEnter,
    logout,
    deleteAccount,
    Toast,
    requestNotification,
    notificationData,
    setNotificationData,
    loginWithSocial,
    downloadCSV,
    setExportLoading,
    exportLoading,
    getProfile,
    getCategory,
    categoryList,
    setCategoryList,
    loacte,
    locationData,
    setLocationData
  };



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

export function useGlobalContext(): GlobalContextType {
  const context = useContext(GlobalContext);
  if (context === undefined) {
    throw new Error("useGlobalContext must be used within a GlobalProvider");
  }
  return context;
}

export default GlobalProvider;
