import { RejectedActionPayload, ServerErrorResponse } from '@/interface/Shared';
import {
  MyAssignment,
  QuizAttemptDetail,
  StartAttemptResponse,
} from '@/interface/Assessment';
import Helpers from '@/utilities/Helpers';
import { createAsyncThunk, createSlice, Draft, PayloadAction } from '@reduxjs/toolkit';
import { message } from 'antd';
import { AttemptsActions } from './actionTypes';
import { apiGet, apiPost, apiPut } from '@/services/api/api';
import axios, { AxiosResponse } from 'axios';

interface AttemptsState {
  currentAttempt: StartAttemptResponse | null;
  attemptResult: QuizAttemptDetail | null;
  myAssignments: MyAssignment[];
  loading: boolean;
  savingProgress: boolean;
  error: string | null;
}

const initialState: AttemptsState = {
  currentAttempt: null,
  attemptResult: null,
  myAssignments: [],
  loading: false,
  savingProgress: false,
  error: null,
};

export const startAttempt = createAsyncThunk(
  AttemptsActions.START_ATTEMPT_REQUEST,
  async (assignmentId: string, { rejectWithValue }) => {
    try {
      const response = (await apiPost('/assessment/attempts/start', {
        assignment_id: assignmentId,
      })) as AxiosResponse<{ data: StartAttemptResponse }>;
      return response.data.data;
    } catch (error) {
      if (axios.isAxiosError(error) && error.response) {
        return rejectWithValue(error.response.data as ServerErrorResponse);
      }
      throw error;
    }
  },
);

export const saveProgress = createAsyncThunk(
  AttemptsActions.SAVE_PROGRESS_REQUEST,
  async (
    payload: {
      attemptId: string;
      answers: {
        question_id: string;
        selected_option_ids?: string[];
        match_answers?: { left_text: string; right_text: string }[];
        short_answer_text?: string | null;
      }[];
      time_remaining_seconds?: number;
    },
    { rejectWithValue },
  ) => {
    try {
      await apiPut(`/assessment/attempts/${payload.attemptId}/progress`, {
        answers: payload.answers,
        time_remaining_seconds: payload.time_remaining_seconds,
      });
      return true;
    } catch (error) {
      if (axios.isAxiosError(error) && error.response) {
        return rejectWithValue(error.response.data as ServerErrorResponse);
      }
      throw error;
    }
  },
);

export const submitAttempt = createAsyncThunk(
  AttemptsActions.SUBMIT_ATTEMPT_REQUEST,
  async (
    payload: {
      attemptId: string;
      answers: {
        question_id: string;
        selected_option_ids?: string[];
        match_answers?: { left_text: string; right_text: string }[];
        short_answer_text?: string | null;
      }[];
      time_remaining_seconds?: number;
    },
    { rejectWithValue },
  ) => {
    try {
      const response = (await apiPost(`/assessment/attempts/${payload.attemptId}/submit`, {
        answers: payload.answers,
        time_remaining_seconds: payload.time_remaining_seconds,
      })) as AxiosResponse<{ data: QuizAttemptDetail }>;
      return response.data.data;
    } catch (error) {
      if (axios.isAxiosError(error) && error.response) {
        return rejectWithValue(error.response.data as ServerErrorResponse);
      }
      throw error;
    }
  },
);

export const fetchAttempt = createAsyncThunk(
  AttemptsActions.FETCH_ATTEMPT_REQUEST,
  async (id: string) => {
    const response = (await apiGet(
      `/assessment/attempts/${id}`,
    )) as AxiosResponse<QuizAttemptDetail>;
    return response.data;
  },
);

export const fetchMyAssignments = createAsyncThunk(
  AttemptsActions.FETCH_MY_ASSIGNMENTS_REQUEST,
  async () => {
    const response = (await apiGet('/assessment/me/assignments')) as AxiosResponse<{
      data: MyAssignment[];
    }>;
    return response.data.data;
  },
);

export const AttemptsSlice = createSlice({
  name: 'assessmentAttempts',
  initialState,
  reducers: {
    clearCurrentAttempt: (state: Draft<AttemptsState>) => {
      state.currentAttempt = null;
      state.attemptResult = null;
    },
  },
  extraReducers(builder) {
    builder
      .addCase(startAttempt.pending, (state: Draft<AttemptsState>) => {
        state.loading = true;
        state.error = null;
      })
      .addCase(
        startAttempt.fulfilled,
        (state: Draft<AttemptsState>, action: PayloadAction<StartAttemptResponse>) => {
          state.currentAttempt = action.payload;
          state.attemptResult = null;
          state.loading = false;
        },
      )
      .addCase(
        startAttempt.rejected,
        (state: Draft<AttemptsState>, action: RejectedActionPayload) => {
          state.loading = false;
          state.error = Helpers.handleServerError(action.payload);
          message.error(Helpers.handleServerError(action.payload), 10);
        },
      );

    builder
      .addCase(saveProgress.pending, (state: Draft<AttemptsState>) => {
        state.savingProgress = true;
      })
      .addCase(saveProgress.fulfilled, (state: Draft<AttemptsState>) => {
        state.savingProgress = false;
      })
      .addCase(saveProgress.rejected, (state: Draft<AttemptsState>) => {
        state.savingProgress = false;
      });

    builder
      .addCase(submitAttempt.pending, (state: Draft<AttemptsState>) => {
        state.loading = true;
        state.error = null;
      })
      .addCase(
        submitAttempt.fulfilled,
        (state: Draft<AttemptsState>, action: PayloadAction<QuizAttemptDetail>) => {
          state.attemptResult = action.payload;
          state.currentAttempt = null;
          state.loading = false;
          message.success('Quiz submitted successfully');
        },
      )
      .addCase(
        submitAttempt.rejected,
        (state: Draft<AttemptsState>, action: RejectedActionPayload) => {
          state.loading = false;
          state.error = Helpers.handleServerError(action.payload);
          message.error(Helpers.handleServerError(action.payload), 10);
        },
      );

    builder
      .addCase(fetchAttempt.pending, (state: Draft<AttemptsState>) => {
        state.loading = true;
      })
      .addCase(
        fetchAttempt.fulfilled,
        (state: Draft<AttemptsState>, action: PayloadAction<QuizAttemptDetail>) => {
          state.attemptResult = action.payload;
          state.loading = false;
        },
      )
      .addCase(fetchAttempt.rejected, (state: Draft<AttemptsState>, action: RejectedActionPayload) => {
        state.loading = false;
        message.error(Helpers.handleServerError(action.payload), 8);
      });

    builder
      .addCase(fetchMyAssignments.pending, (state: Draft<AttemptsState>) => {
        state.loading = true;
      })
      .addCase(
        fetchMyAssignments.fulfilled,
        (state: Draft<AttemptsState>, action: PayloadAction<MyAssignment[]>) => {
          state.myAssignments = action.payload;
          state.loading = false;
        },
      )
      .addCase(fetchMyAssignments.rejected, (state: Draft<AttemptsState>, action: RejectedActionPayload) => {
        state.loading = false;
        message.error(Helpers.handleServerError(action.payload), 8);
      });
  },
});

export const { clearCurrentAttempt } = AttemptsSlice.actions;
export default AttemptsSlice;
export type { AttemptsState };
