import { createSlice, createAsyncThunk, createSelector } from "@reduxjs/toolkit";
import type { RootState } from "@/store/store";
import type {
  Section,
  SectionListPayload,
  SectionListResponse,
} from "@/types/api/section.types";

function cacheKey(p: SectionListPayload) {
  return `${p.is_home_screen}_${p.top_category_id}`;
}

interface PaginationMeta {
  currentPage: number;
  totalPage: number;
  totalRows: number;
  hasMore: boolean;
}

interface FetchResult {
  key: string;
  sections: Section[];
  meta: PaginationMeta;
}

export const fetchSectionList = createAsyncThunk<
  FetchResult,
  SectionListPayload
>(
  "home/fetchSectionList",
  async (payload, { rejectWithValue }) => {
    const key = cacheKey(payload);
    const page = payload.page ?? 1;

    try {
      const { default: apiClient } = await import("@/services/api.client");
      const { API_ENDPOINTS } = await import("@/lib/constants/apiEndpoints");

      const { data } = await apiClient.post<SectionListResponse>(
        API_ENDPOINTS.GET_SECTION_LIST,
        { ...payload, page },
      );

      const sections = (data.result ?? []).filter((s) => s.status === 1);

      // Use `page` from the payload (what we requested), NOT data.current_page.
      // Some APIs always return current_page=1 regardless of the requested page,
      // which would cause the pagination effect to loop forever on page 2.
      return {
        key,
        sections,
        meta: {
          currentPage: page,
          totalPage: data.total_page,
          totalRows: data.total_rows,
          hasMore: data.more_page && page < data.total_page,
        },
      };
    } catch (err) {
      return rejectWithValue((err as Error)?.message ?? "Failed to load sections.");
    }
  },
);

interface HomeState {
  sectionsByKey: Record<string, Section[]>;
  loadedKeys: string[];
  paginationByKey: Record<string, PaginationMeta>;
  isLoading: boolean;
  error: string | null;
}

const initialState: HomeState = {
  sectionsByKey: {},
  loadedKeys: [],
  paginationByKey: {},
  isLoading: false,
  error: null,
};

export const homeSlice = createSlice({
  name: "home",
  initialState,
  reducers: {},
  extraReducers: (builder) => {
    builder
      .addCase(fetchSectionList.pending, (state) => {
        state.isLoading = true;
        state.error = null;
      })
      .addCase(fetchSectionList.fulfilled, (state, action) => {
        state.isLoading = false;
        const { key, sections, meta } = action.payload;

        if (meta.currentPage === 1) {
          // First page — replace any existing data
          state.sectionsByKey[key] = sections;
          if (!state.loadedKeys.includes(key)) {
            state.loadedKeys.push(key);
          }
        } else {
          // Subsequent pages — append, deduplicating by id
          const existing = state.sectionsByKey[key] ?? [];
          const existingIds = new Set(existing.map((s) => s.id));
          const fresh = sections.filter((s) => !existingIds.has(s.id));
          state.sectionsByKey[key] = [...existing, ...fresh];
        }

        state.paginationByKey[key] = meta;
      })
      .addCase(fetchSectionList.rejected, (state, action) => {
        state.isLoading = false;
        state.error = (action.payload as string) ?? "Something went wrong.";
      });
  },
});

export default homeSlice.reducer;

// ── Selectors ────────────────────────────────────────────────────────────────

const EMPTY_SECTIONS: Section[] = [];

const selectSectionsByKey = (state: RootState) =>
  state.home?.sectionsByKey ?? {};

const selectPaginationByKey = (state: RootState) =>
  state.home?.paginationByKey ?? {};

export const selectHomeSections = createSelector(
  selectSectionsByKey,
  (byKey) => byKey["1_0"] ?? EMPTY_SECTIONS,
);

export const selectHomePagination = createSelector(
  selectPaginationByKey,
  (byKey) => byKey["1_0"] ?? null,
);

// Factory: one memoized selector per categoryId
const categorySelectorCache = new Map<
  number,
  ReturnType<typeof createSelector>
>();

export const selectCategorySections = (
  state: RootState,
  categoryId: number,
) => {
  if (!categorySelectorCache.has(categoryId)) {
    categorySelectorCache.set(
      categoryId,
      createSelector(
        selectSectionsByKey,
        (byKey) => byKey[`2_${categoryId}`] ?? EMPTY_SECTIONS,
      ),
    );
  }
  return (categorySelectorCache.get(categoryId) as (s: RootState) => Section[])(state);
};

export const selectCategoryPagination = (
  state: RootState,
  categoryId: number,
) => state.home?.paginationByKey?.[`2_${categoryId}`] ?? null;

export const selectSectionByLayout = (sections: Section[], layout: string) =>
  sections.find((s) => s.screen_layout === layout);

export const selectSectionsByType = (sections: Section[], type: number) =>
  sections.filter((s) => s.type === type);
