import { RejectedActionPayload, ServerErrorResponse } from '@/interface/Shared';
import { apiDownloadBlob, apiGet, apiPost, axiosInstance } from '@/services/api/api';
import Helpers from '@/utilities/Helpers';
import { createAsyncThunk, createSlice, Draft, PayloadAction } from '@reduxjs/toolkit';
import { message } from 'antd';
import axios, { AxiosResponse } from 'axios';
import { ImportBatchResponse, ImportBatchStatus } from './HRImportsSlice';

interface AttendanceHistoryImportsState {
  importBatch: ImportBatchStatus | null;
  importResult: {
    imported_count: number;
    updated_count: number;
    failed_count: number;
    processed_count: number;
    failed_rows_download_url: string | null;
  } | null;
  importing: boolean;
  downloadingTemplate: boolean;
  downloadingFailedRows: boolean;
  error: string | null;
}

const initialState: AttendanceHistoryImportsState = {
  importBatch: null,
  importResult: null,
  importing: false,
  downloadingTemplate: false,
  downloadingFailedRows: false,
  error: null,
};

const resolveFilename = (contentDisposition: string | undefined, fallback: string) => {
  if (!contentDisposition) return fallback;

  const utf8Match = contentDisposition.match(/filename\*=UTF-8''([^;]+)/i);
  if (utf8Match?.[1]) {
    return decodeURIComponent(utf8Match[1]);
  }

  const standardMatch = contentDisposition.match(/filename="?([^";]+)"?/i);
  return standardMatch?.[1] || fallback;
};

const downloadBlob = (blob: Blob, fileName: string) => {
  const url = window.URL.createObjectURL(blob);
  const link = document.createElement('a');
  link.href = url;
  link.setAttribute('download', fileName);
  document.body.appendChild(link);
  link.click();
  link.remove();
  window.URL.revokeObjectURL(url);
};

const parseBlobError = async (data: unknown): Promise<ServerErrorResponse> => {
  if (data instanceof Blob) {
    try {
      return JSON.parse(await data.text()) as ServerErrorResponse;
    } catch {
      return { message: 'An unexpected error occurred. Please try again or contact support.', errors: null };
    }
  }
  return data as ServerErrorResponse;
};

export const executeAttendanceHistoryImport = createAsyncThunk(
  'attendanceHistoryImports/execute',
  async (formData: FormData, { rejectWithValue }) => {
    try {
      const response = (await apiPost('/hr/import/attendance-history', formData, {
        headers: { 'Content-Type': 'multipart/form-data' },
      })) as AxiosResponse<ImportBatchResponse>;

      return response.data;
    } catch (error) {
      if (axios.isAxiosError(error) && error.response) {
        return rejectWithValue(error.response.data as ServerErrorResponse);
      }
      return rejectWithValue({ message: 'An unexpected error occurred. Please try again or contact support.', errors: null });
    }
  },
);

export const fetchAttendanceHistoryImportStatus = createAsyncThunk(
  'attendanceHistoryImports/fetchStatus',
  async (batchId: string, { rejectWithValue }) => {
    try {
      const response = (await apiGet(
        `/hr/import/attendance-history/${batchId}/status`,
      )) as AxiosResponse<ImportBatchStatus>;

      return response.data;
    } catch (error) {
      if (axios.isAxiosError(error) && error.response) {
        return rejectWithValue(error.response.data as ServerErrorResponse);
      }
      return rejectWithValue({ message: 'An unexpected error occurred. Please try again or contact support.', errors: null });
    }
  },
);

export const downloadAttendanceHistoryTemplate = createAsyncThunk(
  'attendanceHistoryImports/downloadTemplate',
  async (_, { rejectWithValue }) => {
    try {
      const response = await apiDownloadBlob('/hr/import/attendance-history/template');
      const filename = resolveFilename(
        response.headers['content-disposition'],
        'attendance_history_import_template.xlsx',
      );
      downloadBlob(new Blob([response.data]), filename);
      return true;
    } catch (error) {
      if (axios.isAxiosError(error) && error.response) {
        return rejectWithValue(await parseBlobError(error.response.data));
      }
      return rejectWithValue({ message: 'An unexpected error occurred. Please try again or contact support.', errors: null });
    }
  },
);

export const downloadAttendanceHistoryFailedRows = createAsyncThunk(
  'attendanceHistoryImports/downloadFailedRows',
  async (downloadUrl: string, { rejectWithValue }) => {
    try {
      const response = await axiosInstance.get(downloadUrl, { responseType: 'blob' });
      const filename = resolveFilename(
        response.headers['content-disposition'],
        'attendance_history_failed_rows.xlsx',
      );
      downloadBlob(new Blob([response.data]), filename);
      return true;
    } catch (error) {
      if (axios.isAxiosError(error) && error.response) {
        return rejectWithValue(await parseBlobError(error.response.data));
      }
      return rejectWithValue({ message: 'An unexpected error occurred. Please try again or contact support.', errors: null });
    }
  },
);

export const AttendanceHistoryImportsSlice = createSlice({
  name: 'attendanceHistoryImports',
  initialState,
  reducers: {
    clearAttendanceHistoryImportState(state) {
      state.importBatch = null;
      state.importResult = null;
      state.error = null;
    },
  },
  extraReducers(builder) {
    builder
      .addCase(
        executeAttendanceHistoryImport.pending,
        (state: Draft<AttendanceHistoryImportsState>) => {
          state.importing = true;
          state.error = null;
        },
      )
      .addCase(
        executeAttendanceHistoryImport.fulfilled,
        (state: Draft<AttendanceHistoryImportsState>, action: PayloadAction<ImportBatchResponse>) => {
          state.importing = false;
          state.importBatch = {
            batch_id: action.payload.batch_id,
            progress: 0,
            finished: false,
            cancelled: false,
            total_jobs: 1,
            pending_jobs: 1,
            processed_jobs: 0,
            failed_jobs: 0,
          };
          message.success(action.payload.message || 'Import job dispatched successfully');
        },
      )
      .addCase(
        executeAttendanceHistoryImport.rejected,
        (state: Draft<AttendanceHistoryImportsState>, action: RejectedActionPayload) => {
          state.importing = false;
          state.error = Helpers.handleServerError(action.payload);
          message.error(state.error, 10);
        },
      );

    builder.addCase(
      fetchAttendanceHistoryImportStatus.fulfilled,
      (state: Draft<AttendanceHistoryImportsState>, action: PayloadAction<ImportBatchStatus>) => {
        state.importBatch = action.payload;

        if (action.payload.finished) {
          state.importResult = {
            imported_count: action.payload.imported_count ?? 0,
            updated_count: action.payload.updated_count ?? 0,
            failed_count: action.payload.failed_count ?? 0,
            processed_count: action.payload.processed_count ?? 0,
            failed_rows_download_url: action.payload.failed_rows_download_url ?? null,
          };
        }
      },
    );

    builder
      .addCase(
        downloadAttendanceHistoryTemplate.pending,
        (state: Draft<AttendanceHistoryImportsState>) => {
          state.downloadingTemplate = true;
          state.error = null;
        },
      )
      .addCase(
        downloadAttendanceHistoryTemplate.fulfilled,
        (state: Draft<AttendanceHistoryImportsState>) => {
          state.downloadingTemplate = false;
        },
      )
      .addCase(
        downloadAttendanceHistoryTemplate.rejected,
        (state: Draft<AttendanceHistoryImportsState>, action: RejectedActionPayload) => {
          state.downloadingTemplate = false;
          state.error = Helpers.handleServerError(action.payload);
          message.error(state.error, 10);
        },
      );

    builder
      .addCase(
        downloadAttendanceHistoryFailedRows.pending,
        (state: Draft<AttendanceHistoryImportsState>) => {
          state.downloadingFailedRows = true;
          state.error = null;
        },
      )
      .addCase(
        downloadAttendanceHistoryFailedRows.fulfilled,
        (state: Draft<AttendanceHistoryImportsState>) => {
          state.downloadingFailedRows = false;
        },
      )
      .addCase(
        downloadAttendanceHistoryFailedRows.rejected,
        (state: Draft<AttendanceHistoryImportsState>, action: RejectedActionPayload) => {
          state.downloadingFailedRows = false;
          state.error = Helpers.handleServerError(action.payload);
          message.error(state.error, 10);
        },
      );
  },
});

export const { clearAttendanceHistoryImportState } = AttendanceHistoryImportsSlice.actions;

export default AttendanceHistoryImportsSlice;
