import { createSlice, createAsyncThunk, type PayloadAction } from "@reduxjs/toolkit";
import type { FeedItem, FeedResponse, FeedDetailResponse, FeedContentUploadResponse } from "@/types/api/feeds.types";
import type { RootState } from "@/store/store";

// ── Fetch feed list ───────────────────────────────────────────────────────────
export const fetchFeed = createAsyncThunk<
  { items: FeedItem[]; currentPage: number; hasMore: boolean; totalRows: number },
  { userId: number; page?: number }
>("feeds/fetch", async ({ userId, page = 1 }, { rejectWithValue }) => {
  try {
    const { default: apiClient } = await import("@/services/api.client");
    const { API_ENDPOINTS } = await import("@/lib/constants/apiEndpoints");
    const { data } = await apiClient.post<FeedResponse>(
      API_ENDPOINTS.GET_FEED,
      { user_id: userId, page },
    );
    return {
      items: (data.result ?? []).filter((f) => f.status === 1),
      currentPage: page,
      hasMore: data.more_page && page < data.total_page,
      totalRows: data.total_rows,
    };
  } catch (err) {
    return rejectWithValue((err as Error)?.message ?? "Failed to load feed.");
  }
});

// ── Fetch single feed detail ──────────────────────────────────────────────────
export const fetchFeedDetail = createAsyncThunk<FeedItem, { feedId: number }>(
  "feeds/fetchDetail",
  async ({ feedId }, { rejectWithValue }) => {
    try {
      const { default: apiClient } = await import("@/services/api.client");
      const { API_ENDPOINTS } = await import("@/lib/constants/apiEndpoints");
      const { data } = await apiClient.post<FeedDetailResponse>(
        API_ENDPOINTS.GET_FEED_DETAIL,
        { feed_id: feedId },
      );
      const feed = data.result?.[0];
      if (!feed) throw new Error("Feed not found");
      return feed;
    } catch (err) {
      return rejectWithValue((err as Error)?.message ?? "Failed to load feed detail.");
    }
  },
);

// ── Delete feed ───────────────────────────────────────────────────────────────
export const deleteFeed = createAsyncThunk<number, { feedId: number }>(
  "feeds/delete",
  async ({ feedId }, { rejectWithValue }) => {
    try {
      const { default: apiClient } = await import("@/services/api.client");
      const { API_ENDPOINTS } = await import("@/lib/constants/apiEndpoints");
      await apiClient.post(API_ENDPOINTS.DELETE_FEED, { feed_id: feedId });
      return feedId;
    } catch (err) {
      return rejectWithValue((err as Error)?.message ?? "Failed to delete feed.");
    }
  },
);

// ── Upload feed content (media) ───────────────────────────────────────────────
export const uploadFeedContent = createAsyncThunk<
  FeedContentUploadResponse["result"],
  { formData: FormData }
>("feeds/uploadContent", async ({ formData }, { rejectWithValue }) => {
  try {
    const { default: apiClient } = await import("@/services/api.client");
    const { API_ENDPOINTS } = await import("@/lib/constants/apiEndpoints");
    const { data } = await apiClient.post<FeedContentUploadResponse>(
      API_ENDPOINTS.FEED_CONTENT_UPLOAD,
      formData,
      { headers: { "Content-Type": "multipart/form-data" } },
    );
    return data.result;
  } catch (err) {
    return rejectWithValue((err as Error)?.message ?? "Upload failed.");
  }
});

// ── Submit new feed post ──────────────────────────────────────────────────────
export const uploadFeed = createAsyncThunk<
  void,
  {
    userId: number;
    categoryId: number;
    title: string;
    description?: string;
    hashtag?: string;
    feedContent: { content_type: string; image: string; video: string }[];
  }
>("feeds/upload", async (payload, { rejectWithValue }) => {
  try {
    const { default: apiClient } = await import("@/services/api.client");
    const { API_ENDPOINTS } = await import("@/lib/constants/apiEndpoints");
    await apiClient.post(API_ENDPOINTS.UPLOAD_FEED, {
      user_id: payload.userId,
      category_id: payload.categoryId,
      title: payload.title,
      description: payload.description ?? "",
      hashtag: payload.hashtag ?? "",
      feed_content: JSON.stringify(payload.feedContent),
    });
  } catch (err) {
    return rejectWithValue((err as Error)?.message ?? "Failed to post feed.");
  }
});

// ── State ─────────────────────────────────────────────────────────────────────
interface FeedsState {
  items: FeedItem[];
  detailById: Record<number, FeedItem>;
  currentPage: number;
  hasMore: boolean;
  totalRows: number;
  isLoading: boolean;
  isPosting: boolean;
  isDeleting: boolean;
  error: string | null;
  selectedFeedId: number | null;
}

const initialState: FeedsState = {
  items: [],
  detailById: {},
  currentPage: 0,
  hasMore: false,
  totalRows: 0,
  isLoading: false,
  isPosting: false,
  isDeleting: false,
  error: null,
  selectedFeedId: null,
};

export const feedsSlice = createSlice({
  name: "feeds",
  initialState,
  reducers: {
    setSelectedFeedId: (state, action: PayloadAction<number | null>) => {
      state.selectedFeedId = action.payload;
    },
    optimisticToggleLike: (state, action: PayloadAction<number>) => {
      const item = state.items.find((f) => f.id === action.payload);
      if (item) {
        item.is_user_like = item.is_user_like === 1 ? 0 : 1;
        item.total_like += item.is_user_like === 1 ? 1 : -1;
      }
    },
  },
  extraReducers: (builder) => {
    builder
      // Fetch list
      .addCase(fetchFeed.pending, (state) => { state.isLoading = true; state.error = null; })
      .addCase(fetchFeed.fulfilled, (state, action) => {
        state.isLoading = false;
        const { items, currentPage, hasMore, totalRows } = action.payload;
        if (currentPage === 1) {
          state.items = items;
        } else {
          const existingIds = new Set(state.items.map((f) => f.id));
          state.items = [...state.items, ...items.filter((f) => !existingIds.has(f.id))];
        }
        state.currentPage = currentPage;
        state.hasMore = hasMore;
        state.totalRows = totalRows;
      })
      .addCase(fetchFeed.rejected, (state, action) => {
        state.isLoading = false;
        state.error = (action.payload as string) ?? "Something went wrong.";
      })
      // Detail
      .addCase(fetchFeedDetail.fulfilled, (state, action) => {
        state.detailById[action.payload.id] = action.payload;
      })
      // Delete
      .addCase(deleteFeed.pending, (state) => { state.isDeleting = true; })
      .addCase(deleteFeed.fulfilled, (state, action) => {
        state.isDeleting = false;
        state.items = state.items.filter((f) => f.id !== action.payload);
        if (state.selectedFeedId === action.payload) state.selectedFeedId = null;
      })
      .addCase(deleteFeed.rejected, (state) => { state.isDeleting = false; })
      // Post new
      .addCase(uploadFeed.pending, (state) => { state.isPosting = true; })
      .addCase(uploadFeed.fulfilled, (state) => { state.isPosting = false; })
      .addCase(uploadFeed.rejected, (state) => { state.isPosting = false; });
  },
});

export const { setSelectedFeedId, optimisticToggleLike } = feedsSlice.actions;
export default feedsSlice.reducer;

export const selectFeedItems     = (s: RootState) => s.feeds.items;
export const selectFeedsLoading  = (s: RootState) => s.feeds.isLoading;
export const selectFeedsHasMore  = (s: RootState) => s.feeds.hasMore;
export const selectFeedsPage     = (s: RootState) => s.feeds.currentPage;
export const selectFeedsPosting  = (s: RootState) => s.feeds.isPosting;
export const selectFeedsDeleting = (s: RootState) => s.feeds.isDeleting;
export const selectSelectedFeed  = (s: RootState) => s.feeds.selectedFeedId;
export const selectFeedDetail    = (id: number) => (s: RootState) => s.feeds.detailById[id] ?? null;
