import { createSlice, createAsyncThunk, type PayloadAction } from "@reduxjs/toolkit";
import type { ContentDetailItem, ContentDetailResponse } from "@/types/api/contentDetail.types";
import type { RootState } from "@/store/store";

type CacheKey = `${number}_${number}`; // `type_id`

export const fetchContentDetail = createAsyncThunk<
  { key: CacheKey; item: ContentDetailItem },
  { type: number; contentId: number; userId?: number }
>("contentDetail/fetch", async ({ type, contentId, userId = 0 }, { rejectWithValue }) => {
  try {
    const { default: apiClient } = await import("@/services/api.client");
    const { API_ENDPOINTS } = await import("@/lib/constants/apiEndpoints");
    const { data } = await apiClient.post<ContentDetailResponse>(
      API_ENDPOINTS.GET_CONTENT_DETAIL,
      { type, content_id: contentId, user_id: userId },
    );
    const item = data.result?.[0];
    if (!item) throw new Error("Content not found");
    return { key: `${type}_${contentId}`, item };
  } catch (err) {
    return rejectWithValue((err as Error)?.message ?? "Failed to load content.");
  }
});

export const toggleLike = createAsyncThunk<
  { key: CacheKey; liked: boolean; message: string },
  { type: number; contentId: number; userId: number; videoId?: number; currentLiked: boolean }
>("contentDetail/toggleLike", async ({ type, contentId, userId, videoId = 0, currentLiked }, { rejectWithValue }) => {
  try {
    const { default: apiClient } = await import("@/services/api.client");
    const { API_ENDPOINTS } = await import("@/lib/constants/apiEndpoints");
    const { data } = await apiClient.post<{ status: number; message: string; result: unknown[] }>(
      API_ENDPOINTS.LIKE_UNLIKE,
      { user_id: userId, type, content_id: contentId, video_id: videoId },
    );
    return { key: `${type}_${contentId}`, liked: !currentLiked, message: data.message ?? "" };
  } catch (err) {
    return rejectWithValue((err as Error)?.message ?? "Failed.");
  }
});

export const toggleBookmark = createAsyncThunk<
  { key: CacheKey; bookmarked: boolean; message: string },
  { type: number; contentId: number; userId: number; currentBookmarked: boolean }
>("contentDetail/toggleBookmark", async ({ type, contentId, userId, currentBookmarked }, { rejectWithValue }) => {
  try {
    const { default: apiClient } = await import("@/services/api.client");
    const { API_ENDPOINTS } = await import("@/lib/constants/apiEndpoints");
    const { data } = await apiClient.post<{ status: number; message: string; result: unknown[] }>(
      API_ENDPOINTS.ADD_BOOKMARK,
      { user_id: userId, type, content_id: contentId },
    );
    return { key: `${type}_${contentId}`, bookmarked: !currentBookmarked, message: data.message ?? "" };
  } catch (err) {
    return rejectWithValue((err as Error)?.message ?? "Failed.");
  }
});

export const fetchRelatedContent = createAsyncThunk<
  { key: CacheKey; items: ContentDetailItem[] },
  { type: number; contentId: number; languageId: number; userId?: number }
>("contentDetail/fetchRelated", async ({ type, contentId, languageId, userId = 0 }, { rejectWithValue }) => {
  try {
    const { default: apiClient } = await import("@/services/api.client");
    const { API_ENDPOINTS } = await import("@/lib/constants/apiEndpoints");
    const { data } = await apiClient.post<ContentDetailResponse>(
      API_ENDPOINTS.GET_RELATED_CONTENT,
      { type, content_id: contentId, language_id: languageId, user_id: userId },
    );
    return { key: `${type}_${contentId}`, items: (data.result ?? []).filter((i) => i.status === 1) };
  } catch (err) {
    return rejectWithValue((err as Error)?.message ?? "Failed to load related content.");
  }
});

interface ContentDetailState {
  byKey: Record<CacheKey, ContentDetailItem>;
  relatedByKey: Record<CacheKey, ContentDetailItem[]>;
  loadedKeys: CacheKey[];
  isLoading: boolean;
  error: string | null;
}

const initialState: ContentDetailState = {
  byKey: {},
  relatedByKey: {},
  loadedKeys: [],
  isLoading: false,
  error: null,
};

export const contentDetailSlice = createSlice({
  name: "contentDetail",
  initialState,
  reducers: {
    optimisticLike: (state, action: PayloadAction<CacheKey>) => {
      const item = state.byKey[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;
      }
    },
    optimisticBookmark: (state, action: PayloadAction<CacheKey>) => {
      const item = state.byKey[action.payload];
      if (item) {
        item.is_user_bookmark = item.is_user_bookmark === 1 ? 0 : 1;
      }
    },
  },
  extraReducers: (builder) => {
    builder
      .addCase(fetchContentDetail.pending, (state) => { state.isLoading = true; state.error = null; })
      .addCase(fetchContentDetail.fulfilled, (state, action) => {
        state.isLoading = false;
        const { key, item } = action.payload;
        state.byKey[key] = item;
        if (!state.loadedKeys.includes(key)) state.loadedKeys.push(key);
      })
      .addCase(fetchContentDetail.rejected, (state, action) => {
        state.isLoading = false;
        state.error = (action.payload as string) ?? "Something went wrong.";
      })
      .addCase(fetchRelatedContent.fulfilled, (state, action) => {
        const { key, items } = action.payload;
        state.relatedByKey[key] = items;
      });
  },
});

export const { optimisticLike, optimisticBookmark } = contentDetailSlice.actions;
export default contentDetailSlice.reducer;

export const selectContentDetail   = (type: number, id: number) => (s: RootState) => s.contentDetail.byKey[`${type}_${id}` as CacheKey] ?? null;
export const selectContentLoading  = (s: RootState) => s.contentDetail.isLoading;
export const selectContentLoaded   = (type: number, id: number) => (s: RootState) => s.contentDetail.loadedKeys.includes(`${type}_${id}` as CacheKey);
export const selectRelatedContent  = (type: number, id: number) => (s: RootState) => s.contentDetail.relatedByKey[`${type}_${id}` as CacheKey] ?? null;
export type { CacheKey };
