import { createSlice, createAsyncThunk, type PayloadAction } from "@reduxjs/toolkit";
import type { RootState } from "@/store/store";

export interface CommentItem {
  id: number;
  comment_id: number;
  user_id: number;
  type: number;
  content_id: number;
  video_id: number;
  comment: string;
  status: number;
  created_at: string;
  updated_at: string;
  user_name: string;
  user_image: string;
  is_reply_comment: number;
  replies?: CommentItem[];
}

interface CommentResponse {
  status: number;
  message: string;
  result: CommentItem[];
  total_rows: number;
  total_page: number;
  current_page: number;
  more_page: boolean;
}

type ContentKey = `${number}_${number}_${number}`; // type_contentId_videoId

function makeKey(type: number, contentId: number, videoId = 0): ContentKey {
  return `${type}_${contentId}_${videoId}`;
}

// ── Thunks ────────────────────────────────────────────────────────────────────
export const fetchComments = createAsyncThunk<
  { key: ContentKey; comments: CommentItem[] },
  { type: number; contentId: number; videoId?: number }
>("comments/fetch", async ({ type, contentId, videoId = 0 }, { rejectWithValue }) => {
  try {
    const { default: apiClient } = await import("@/services/api.client");
    const { API_ENDPOINTS } = await import("@/lib/constants/apiEndpoints");
    const { data } = await apiClient.post<CommentResponse>(
      API_ENDPOINTS.GET_COMMENT,
      { type, content_id: contentId, video_id: videoId },
    );
    return { key: makeKey(type, contentId, videoId), comments: data.result ?? [] };
  } catch (err) {
    return rejectWithValue((err as Error)?.message ?? "Failed to load comments.");
  }
});

export const fetchReplies = createAsyncThunk<
  { parentId: number; key: ContentKey; replies: CommentItem[] },
  { commentId: number; contentKey: ContentKey }
>("comments/fetchReplies", async ({ commentId, contentKey }, { rejectWithValue }) => {
  try {
    const { default: apiClient } = await import("@/services/api.client");
    const { API_ENDPOINTS } = await import("@/lib/constants/apiEndpoints");
    const { data } = await apiClient.post<CommentResponse>(
      API_ENDPOINTS.GET_REPLY_COMMENT,
      { comment_id: commentId },
    );
    return { parentId: commentId, key: contentKey, replies: data.result ?? [] };
  } catch (err) {
    return rejectWithValue((err as Error)?.message ?? "Failed to load replies.");
  }
});

export const addComment = createAsyncThunk<
  // The API returns result:[] so we construct the item locally from the payload
  CommentItem,
  { userId: number; contentId: number; type: number; comment: string; commentId?: number; videoId?: number; contentKey: ContentKey; userName?: string; userImage?: string }
>("comments/add", async ({ userId, contentId, type, comment, commentId = 0, videoId = 0, userName = "You", userImage = "" }, { rejectWithValue }) => {
  try {
    const { default: apiClient } = await import("@/services/api.client");
    const { API_ENDPOINTS } = await import("@/lib/constants/apiEndpoints");
    await apiClient.post(
      API_ENDPOINTS.ADD_COMMENT,
      { user_id: userId, content_id: contentId, type, comment, comment_id: commentId, video_id: videoId },
    );
    // API returns empty result — build a local optimistic item
    const localItem: CommentItem = {
      id: Date.now(), // temporary id until page refreshes
      comment_id: commentId,
      user_id: userId,
      type,
      content_id: contentId,
      video_id: videoId,
      comment,
      status: 1,
      created_at: new Date().toISOString(),
      updated_at: new Date().toISOString(),
      user_name: userName,
      user_image: userImage,
      is_reply_comment: commentId > 0 ? 1 : 0,
    };
    return localItem;
  } catch (err) {
    return rejectWithValue((err as Error)?.message ?? "Failed to add comment.");
  }
});

export const editComment = createAsyncThunk<
  { commentId: number; text: string; contentKey: ContentKey },
  { commentId: number; comment: string; contentKey: ContentKey }
>("comments/edit", async ({ commentId, comment, contentKey }, { rejectWithValue }) => {
  try {
    const { default: apiClient } = await import("@/services/api.client");
    const { API_ENDPOINTS } = await import("@/lib/constants/apiEndpoints");
    await apiClient.post(API_ENDPOINTS.EDIT_COMMENT, { comment_id: commentId, comment });
    return { commentId, text: comment, contentKey };
  } catch (err) {
    return rejectWithValue((err as Error)?.message ?? "Failed to edit comment.");
  }
});

export const deleteComment = createAsyncThunk<
  { commentId: number; contentKey: ContentKey },
  { commentId: number; contentKey: ContentKey }
>("comments/delete", async ({ commentId, contentKey }, { rejectWithValue }) => {
  try {
    const { default: apiClient } = await import("@/services/api.client");
    const { API_ENDPOINTS } = await import("@/lib/constants/apiEndpoints");
    await apiClient.post(API_ENDPOINTS.DELETE_COMMENT, { comment_id: commentId });
    return { commentId, contentKey };
  } catch (err) {
    return rejectWithValue((err as Error)?.message ?? "Failed to delete comment.");
  }
});

// ── State ─────────────────────────────────────────────────────────────────────
interface CommentState {
  byKey: Record<ContentKey, CommentItem[]>;
  loadedKeys: ContentKey[];
  isLoading: boolean;
  isSubmitting: boolean;
}

const initialState: CommentState = {
  byKey: {},
  loadedKeys: [],
  isLoading: false,
  isSubmitting: false,
};

export const commentSlice = createSlice({
  name: "comments",
  initialState,
  reducers: {
    clearComments: (state, action: PayloadAction<ContentKey>) => {
      delete state.byKey[action.payload];
      state.loadedKeys = state.loadedKeys.filter((k) => k !== action.payload);
    },
  },
  extraReducers: (builder) => {
    builder
      .addCase(fetchComments.pending, (state) => { state.isLoading = true; })
      .addCase(fetchComments.fulfilled, (state, action) => {
        state.isLoading = false;
        const { key, comments } = action.payload;
        state.byKey[key] = comments;
        if (!state.loadedKeys.includes(key)) state.loadedKeys.push(key);
      })
      .addCase(fetchComments.rejected, (state) => { state.isLoading = false; })

      .addCase(fetchReplies.fulfilled, (state, action) => {
        const { parentId, key, replies } = action.payload;
        if (state.byKey[key]) {
          state.byKey[key] = state.byKey[key].map((c) =>
            c.id === parentId ? { ...c, replies } : c,
          );
        }
      })

      .addCase(addComment.pending, (state) => { state.isSubmitting = true; })
      .addCase(addComment.fulfilled, (state, action) => {
        state.isSubmitting = false;
        const c = action.payload;
        if (!c) return;
        const key = action.meta.arg.contentKey;
        if (!state.byKey[key]) state.byKey[key] = [];
        if (action.meta.arg.commentId) {
          // It's a reply — append under parent
          state.byKey[key] = state.byKey[key].map((parent) =>
            parent.id === action.meta.arg.commentId
              ? { ...parent, replies: [...(parent.replies ?? []), c] }
              : parent,
          );
        } else {
          state.byKey[key] = [c, ...state.byKey[key]];
        }
      })
      .addCase(addComment.rejected, (state) => { state.isSubmitting = false; })

      .addCase(editComment.fulfilled, (state, action) => {
        const { commentId, text, contentKey } = action.payload;
        if (state.byKey[contentKey]) {
          state.byKey[contentKey] = state.byKey[contentKey].map((c) =>
            c.id === commentId ? { ...c, comment: text }
              : { ...c, replies: (c.replies ?? []).map((r) => r.id === commentId ? { ...r, comment: text } : r) },
          );
        }
      })

      .addCase(deleteComment.fulfilled, (state, action) => {
        const { commentId, contentKey } = action.payload;
        if (state.byKey[contentKey]) {
          state.byKey[contentKey] = state.byKey[contentKey]
            .filter((c) => c.id !== commentId)
            .map((c) => ({ ...c, replies: (c.replies ?? []).filter((r) => r.id !== commentId) }));
        }
      });
  },
});

export const { clearComments } = commentSlice.actions;
export default commentSlice.reducer;

export const selectComments = (key: ContentKey) => (s: RootState) => s.comments.byKey[key] ?? [];
export const selectCommentsLoaded = (key: ContentKey) => (s: RootState) => s.comments.loadedKeys.includes(key);
export const selectCommentsLoading = (s: RootState) => s.comments.isLoading;
export const selectCommentsSubmitting = (s: RootState) => s.comments.isSubmitting;
export { makeKey, type ContentKey };
