/** @format */

import { createStore } from "zustand/vanilla";
import { privateInstance } from "@/configs/axiosConfig";
import { storage } from "@/configs/storage";

export interface WishlistItem {
  id: number;
  project_id: number;
  title: string;
  slug: string;
  code: string;
  thumbnail: string;
}

export interface WishlistState {
  items: WishlistItem[];
  isLoggedIn: boolean;
}

export type WishlistActions = {
  addItem: (item: WishlistItem) => void;
  removeItem: (id: number) => void;
  removeByProjectId: (projectId: number) => void;
  getItems: () => WishlistItem[];
  setItems: (items: WishlistItem[]) => void;
  setLoggedIn: (loggedIn: boolean) => void;
  loadFromStorage: () => void;
  mergeItems: (serverItems: WishlistItem[]) => void;
  backup: () => void;
  restore: () => void;
  fetchFromServer: () => Promise<void>;
};

export type WishlistStore = WishlistState & WishlistActions;

export const STORAGE_KEY = "investra_wishlist";
export const BACKUP_KEY = "investra_wishlist_backup";

const getLS = async (key: string): Promise<WishlistItem[]> => {
  if (typeof window === "undefined") return [];
  try {
    const value = storage.getString(key);
    return JSON.parse(value || "[]");
  } catch {
    return [];
  }
};

const setLS = async (key: string, items: WishlistItem[]) => {
  if (typeof window === "undefined") return;
  storage.set(key, JSON.stringify(items));
};

const removeLS = async (key: string) => {
  if (typeof window === "undefined") return;
  storage.remove(key);
};

export const defaultInitState: WishlistState = {
  items: [],
  isLoggedIn: false,
};

export const createWishlistStore = (
  initState: WishlistState = defaultInitState,
) => {
  return createStore<WishlistStore>((set, get) => ({
    ...initState,

    addItem: (item: WishlistItem) => {
      const { items } = get();
      if (items.some((i) => i.project_id === item.project_id)) return;
      const newItems = [...items, item];
      set({ items: newItems });
      setLS(STORAGE_KEY, newItems);
    },

    removeItem: (id: number) => {
      const { items } = get();
      const newItems = items.filter((i) => i.id !== id);
      set({ items: newItems });
      setLS(STORAGE_KEY, newItems);
    },

    removeByProjectId: (projectId: number) => {
      const { items } = get();
      const newItems = items.filter((i) => i.project_id !== projectId);
      set({ items: newItems });
      setLS(STORAGE_KEY, newItems);
    },

    getItems: () => get().items,

    setItems: (items: WishlistItem[]) => {
      set({ items });
      setLS(STORAGE_KEY, items);
    },

    setLoggedIn: (loggedIn: boolean) => set({ isLoggedIn: loggedIn }),

    loadFromStorage: async () => {
      const items = await getLS(STORAGE_KEY);
      set({ items });
    },

    fetchFromServer: async () => {
      try {
        const res = await privateInstance.get("/wishlist");
        const serverItems = res.data?.data || [];
        get().mergeItems(serverItems);
      } catch (err) {
        console.warn("Failed to fetch wishlist:", err);
      }
    },

    mergeItems: (serverItems: WishlistItem[]) => {
      const currentItems = get().items;

      // 1. First, map local guest items to server items to get DB IDs
      const updatedItems = currentItems.map((localItem) => {
        const serverMatch = serverItems.find(
          (si) => si.project_id === localItem.project_id,
        );
        if (serverMatch) {
          // Keep local metadata but use the real server ID for deletion
          return { ...localItem, id: serverMatch.id };
        }
        return localItem;
      });

      // 2. Then, pick up items that are on the server but not in local at all
      const localProjectIds = new Set(updatedItems.map((i) => i.project_id));
      const newlyAddedFromServer = serverItems.filter(
        (si) => !localProjectIds.has(si.project_id),
      );

      const finalItems = [...updatedItems, ...newlyAddedFromServer];

      set({ items: finalItems });
      setLS(STORAGE_KEY, finalItems);
    },

    backup: async () => {
      // Clones the guest wishlist before merging with account data
      const items = await getLS(STORAGE_KEY);
      await setLS(BACKUP_KEY, items);
    },

    restore: async () => {
      // Restores the original guest wishlist on logout
      const items = await getLS(BACKUP_KEY);

      set({ items });

      await setLS(STORAGE_KEY, items);
      await removeLS(BACKUP_KEY);
    },
  }));
};
