import { RejectedActionPayload, ServerErrorResponse } from '@/interface/Shared';
import {
  PublicAssessmentInfo,
  PublicStartResponse,
  PublicSubmitResponse,
  StartRecruitmentAttemptPayload,
} from '@/interface/Assessment';
import Helpers from '@/utilities/Helpers';
import { createAsyncThunk, createSlice } from '@reduxjs/toolkit';
import { PublicAssessmentActions } from './actionTypes';
import { apiGet, apiPost, apiPut } from '@/services/api/api';
import axios, { AxiosResponse } from 'axios';

interface PublicAssessmentState {
  info: PublicAssessmentInfo | null;
  startResponse: PublicStartResponse | null;
  submitResult: PublicSubmitResponse | null;
  alreadyCompleted: { score: string; percentage: string; passed: boolean } | null;
  loading: boolean;
  submitting: boolean;
  error: string | null;
}

const initialState: PublicAssessmentState = {
  info: null,
  startResponse: null,
  submitResult: null,
  alreadyCompleted: null,
  loading: false,
  submitting: false,
  error: null,
};

export const fetchPublicAssessment = createAsyncThunk<
  PublicAssessmentInfo,
  string,
  { rejectValue: RejectedActionPayload }
>(PublicAssessmentActions.FETCH_INFO_REQUEST, async (token, thunkAPI) => {
  try {
    const response: AxiosResponse = await apiGet(`/assessment/public/recruitment/${token}`);
    return response.data.data;
  } catch (error) {
    if (axios.isAxiosError(error)) {
      return thunkAPI.rejectWithValue(error.response?.data as ServerErrorResponse);
    }
    throw error;
  }
});

export const startPublicAttempt = createAsyncThunk<
  PublicStartResponse,
  { token: string; payload: StartRecruitmentAttemptPayload },
  { rejectValue: RejectedActionPayload }
>(PublicAssessmentActions.START_ATTEMPT_REQUEST, async ({ token, payload }, thunkAPI) => {
  try {
    const response: AxiosResponse = await apiPost(
      `/assessment/public/recruitment/${token}/start`,
      payload,
    );
    return response.data.data;
  } catch (error) {
    if (axios.isAxiosError(error)) {
      const status = error.response?.status;
      const data = error.response?.data;

      if (status === 409) {
        let parsed = data;
        if (typeof data?.message === 'string') {
          try {
            parsed = JSON.parse(data.message);
          } catch {
            parsed = data;
          }
        }
        if (parsed?.status === 'already_completed') {
          return thunkAPI.rejectWithValue({
            ...parsed,
            _alreadyCompleted: true,
          } as any);
        }
      }
      return thunkAPI.rejectWithValue(data as ServerErrorResponse);
    }
    throw error;
  }
});

export const savePublicProgress = createAsyncThunk<
  void,
  {
    attemptId: string;
    answers: any[];
    time_remaining_seconds?: number;
  },
  { rejectValue: RejectedActionPayload }
>(PublicAssessmentActions.SAVE_PROGRESS_REQUEST, async (params, thunkAPI) => {
  try {
    await apiPut(`/assessment/public/recruitment/attempts/${params.attemptId}/progress`, {
      answers: params.answers,
      time_remaining_seconds: params.time_remaining_seconds,
    });
  } catch (error) {
    if (axios.isAxiosError(error)) {
      return thunkAPI.rejectWithValue(error.response?.data as ServerErrorResponse);
    }
    throw error;
  }
});

export const submitPublicAttempt = createAsyncThunk<
  PublicSubmitResponse,
  {
    attemptId: string;
    answers: any[];
    time_remaining_seconds?: number;
  },
  { rejectValue: RejectedActionPayload }
>(PublicAssessmentActions.SUBMIT_ATTEMPT_REQUEST, async (params, thunkAPI) => {
  try {
    const response: AxiosResponse = await apiPost(
      `/assessment/public/recruitment/attempts/${params.attemptId}/submit`,
      {
        answers: params.answers,
        time_remaining_seconds: params.time_remaining_seconds,
      },
    );
    return response.data.data;
  } catch (error) {
    if (axios.isAxiosError(error)) {
      return thunkAPI.rejectWithValue(error.response?.data as ServerErrorResponse);
    }
    throw error;
  }
});

const PublicAssessmentSlice = createSlice({
  name: 'publicAssessment',
  initialState,
  reducers: {
    resetPublicAssessment: () => initialState,
  },
  extraReducers: (builder) => {
    builder
      .addCase(fetchPublicAssessment.pending, (state) => {
        state.loading = true;
        state.error = null;
      })
      .addCase(fetchPublicAssessment.fulfilled, (state, action) => {
        state.loading = false;
        state.info = action.payload;
      })
      .addCase(fetchPublicAssessment.rejected, (state, action) => {
        state.loading = false;
        state.error = (action.payload as any)?.message || 'Assessment not found or expired.';
      })

      .addCase(startPublicAttempt.pending, (state) => {
        state.loading = true;
        state.error = null;
      })
      .addCase(startPublicAttempt.fulfilled, (state, action) => {
        state.loading = false;
        state.startResponse = action.payload;
      })
      .addCase(startPublicAttempt.rejected, (state, action) => {
        state.loading = false;
        const payload = action.payload as any;
        if (payload?._alreadyCompleted) {
          state.alreadyCompleted = {
            score: payload.score,
            percentage: payload.percentage,
            passed: payload.passed,
          };
        } else {
          state.error = payload?.message || 'Failed to start assessment.';
        }
      })

      .addCase(submitPublicAttempt.pending, (state) => {
        state.submitting = true;
      })
      .addCase(submitPublicAttempt.fulfilled, (state, action) => {
        state.submitting = false;
        state.submitResult = action.payload;
      })
      .addCase(submitPublicAttempt.rejected, (state, action) => {
        state.submitting = false;
        Helpers.handleServerError(action.payload);
      });
  },
});

export const { resetPublicAssessment } = PublicAssessmentSlice.actions;
export default PublicAssessmentSlice;
