import { createSlice, createAsyncThunk, PayloadAction } from "@reduxjs/toolkit";
import type { RootState } from "@/store/store";
import apiClient from "@/lib/axiosClient";
import { API_ENDPOINTS } from "@/lib/apiEndpoints";
import type { ApiListing } from "@/types/marketplace";
import { fetchListings } from "./marketplaceListingsSlice";
import { fetchListingDetail } from "./marketplaceListingDetailSlice";

interface Toast {
  message: string;
  key: number;
}

interface WishlistState {
  ids: string[];
  listings: ApiListing[];
  isLoading: boolean;
  toggling: string[];
  toast: Toast | null;
  error: string | null;
}

const initialState: WishlistState = {
  ids: [],
  listings: [],
  isLoading: false,
  toggling: [],
  toast: null,
  error: null,
};

export const fetchWishlist = createAsyncThunk(
  "marketplaceWishlist/fetch",
  async (_force: boolean, { rejectWithValue }) => {
    try {
      const res = await apiClient.post(API_ENDPOINTS.CLASSIFIED.GET_WISHLIST, {});
      return (res.data.result ?? []) as ApiListing[];
    } catch (err: unknown) {
      return rejectWithValue(err instanceof Error ? err.message : "Failed");
    }
  },
  {
    /* condition runs BEFORE pending is dispatched — safe to read isLoading here */
    condition: (force: boolean, { getState }) => {
      const state = (getState() as RootState).marketplaceWishlist;
      if (state.isLoading) return false;       // prevent concurrent calls
      if (!force && state.ids.length > 0) return false; // use cache when not forced
      return true;
    },
  }
);

export const toggleWishlist = createAsyncThunk(
  "marketplaceWishlist/toggle",
  async (listingId: string, { rejectWithValue }) => {
    try {
      const res = await apiClient.post(API_ENDPOINTS.CLASSIFIED.TOGGLE_WISHLIST, {
        listing_id: Number(listingId),
      });
      return { listingId, message: (res.data.message as string) ?? "Done" };
    } catch (err: unknown) {
      return rejectWithValue({ listingId, message: err instanceof Error ? err.message : "Failed" });
    }
  }
);

let toastCounter = 0;

const marketplaceWishlistSlice = createSlice({
  name: "marketplaceWishlist",
  initialState,
  reducers: {
    /* Optimistic toggle — called before the API round-trip */
    optimisticToggle(state, action: PayloadAction<string>) {
      const id = action.payload;
      if (state.ids.includes(id)) {
        state.ids = state.ids.filter((i) => i !== id);
        state.listings = state.listings.filter((l) => String(l.id) !== id);
      } else {
        state.ids = [...state.ids, id];
      }
    },
    /* Revert optimistic toggle on API failure */
    revertToggle(state, action: PayloadAction<string>) {
      const id = action.payload;
      if (state.ids.includes(id)) {
        state.ids = state.ids.filter((i) => i !== id);
        state.listings = state.listings.filter((l) => String(l.id) !== id);
      } else {
        state.ids = [...state.ids, id];
      }
    },
    clearToast(state) {
      state.toast = null;
    },
  },
  extraReducers: (builder) => {
    builder
      /* fetch wishlist */
      .addCase(fetchWishlist.pending, (state) => {
        state.isLoading = true;
        state.error = null;
      })
      .addCase(fetchWishlist.fulfilled, (state, action) => {
        state.isLoading = false;
        if (action.payload) {
          state.listings = action.payload;
          state.ids = action.payload.map((l) => String(l.id));
        }
      })
      .addCase(fetchWishlist.rejected, (state, action) => {
        state.isLoading = false;
        state.error = action.payload as string;
      })

      /* toggle wishlist */
      .addCase(toggleWishlist.pending, (state, action) => {
        state.toggling = [...state.toggling, action.meta.arg];
      })
      .addCase(toggleWishlist.fulfilled, (state, action) => {
        const { listingId, message } = action.payload;
        state.toggling = state.toggling.filter((id) => id !== listingId);
        state.toast = { message, key: ++toastCounter };
      })
      .addCase(toggleWishlist.rejected, (state, action) => {
        const payload = action.payload as { listingId: string; message: string };
        state.toggling = state.toggling.filter((id) => id !== payload?.listingId);
        /* revert already happened via optimisticToggle — we add it back here */
        if (payload?.listingId) {
          const id = payload.listingId;
          if (state.ids.includes(id)) {
            state.ids = state.ids.filter((i) => i !== id);
          } else {
            state.ids = [...state.ids, id];
          }
        }
      })

      /* Seed wishlist IDs from is_wishlist flag in listings responses */
      .addCase(fetchListings.fulfilled, (state, action) => {
        const incomingIds = action.payload.listings
          .filter((l) => l.is_wishlist === 1)
          .map((l) => String(l.id));
        if (incomingIds.length === 0) return;
        const merged = new Set(state.ids);
        incomingIds.forEach((id) => merged.add(id));
        state.ids = Array.from(merged);
      })

      /* Seed from listing detail page too */
      .addCase(fetchListingDetail.fulfilled, (state, action) => {
        if (!action.payload?.listing) return;
        const { listing } = action.payload;
        const id = String(listing.id);
        if (listing.is_wishlist === 1) {
          if (!state.ids.includes(id)) state.ids = [...state.ids, id];
        } else {
          /* If API says not wishlisted and we haven't explicitly added it via toggle, remove it */
          state.ids = state.ids.filter((i) => i !== id);
        }
      });
  },
});

export const { optimisticToggle, revertToggle, clearToast } =
  marketplaceWishlistSlice.actions;
export default marketplaceWishlistSlice.reducer;
