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 { HRImportsActions } from './actionTypes';

export interface AvailableField {
  key: string;
  label: string;
}

export interface PreviewResponse {
  headers: string[];
  sample_rows: (string | number | null)[][];
  suggested_mapping: Record<string, string | null>;
  available_fields: AvailableField[];
  sheet_names: string[];
  active_sheet: string;
  header_row: number;
  total_data_rows: number;
  temp_file_path: string;
}

export interface ImportResponse {
  message: string;
  validate_only: boolean;
  imported_count: number;
  updated_count: number;
  failed_count: number;
  processed_count: number;
  failed_rows_file: string | null;
  failed_rows_download_url: string | null;
  preview_rows?: Record<string, unknown>[];
}

export interface ImportBatchResponse {
  message: string;
  batch_id: string;
}

export interface ImportBatchStatus {
  batch_id: string;
  progress: number;
  finished: boolean;
  cancelled: boolean;
  total_jobs: number;
  pending_jobs: number;
  processed_jobs: number;
  failed_jobs: number;
  imported_count?: number;
  updated_count?: number;
  failed_count?: number;
  processed_count?: number;
  failed_rows_download_url?: string | null;
}

export interface IDCardValidationResponse extends ImportResponse {
  temp_file_path: string;
  temp_images_path: string;
  total_images: number;
}

interface HRImportsState {
  previewData: PreviewResponse | null;
  columnMapping: Record<string, string | null>;
  validationResult: ImportResponse | null;
  importResult: ImportResponse | null;
  importBatch: ImportBatchStatus | null;
  previewing: boolean;
  validating: boolean;
  importing: boolean;
  downloadingTemplate: boolean;
  downloadingFailedRows: boolean;
  idCardTempFilePath: string | null;
  idCardTempImagesPath: string | null;
  error: string | null;
}

const initialState: HRImportsState = {
  previewData: null,
  columnMapping: {},
  validationResult: null,
  importResult: null,
  importBatch: null,
  previewing: false,
  validating: false,
  importing: false,
  downloadingTemplate: false,
  downloadingFailedRows: false,
  idCardTempFilePath: null,
  idCardTempImagesPath: null,
  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);
};

export const previewImportFile = createAsyncThunk(
  HRImportsActions.PREVIEW_FILE,
  async (
    payload: { file: File; headerRow?: number; sheetName?: string },
    { rejectWithValue },
  ) => {
    try {
      const formData = new FormData();
      formData.append('file', payload.file);
      if (payload.headerRow) {
        formData.append('header_row', String(payload.headerRow));
      }
      if (payload.sheetName) {
        formData.append('sheet_name', payload.sheetName);
      }

      const response = (await apiPost('/hr/import/employees/preview', formData, {
        headers: { 'Content-Type': 'multipart/form-data' },
      })) as AxiosResponse<PreviewResponse>;

      return response.data;
    } catch (error) {
      if (axios.isAxiosError(error) && error.response) {
        return rejectWithValue(error.response.data as ServerErrorResponse);
      }
      throw error;
    }
  },
);

export const validateHRImport = createAsyncThunk(
  HRImportsActions.VALIDATE_IMPORT,
  async (
    payload: { file: File; columnMapping: Record<string, string | null>; headerRow?: number },
    { rejectWithValue },
  ) => {
    try {
      const formData = new FormData();
      formData.append('file', payload.file);
      formData.append('validate_only', '1');
      if (payload.headerRow) {
        formData.append('header_row', String(payload.headerRow));
      }

      Object.entries(payload.columnMapping).forEach(([key, value]) => {
        formData.append(`column_mapping[${key}]`, value ?? '');
      });

      const response = (await apiPost('/hr/import/employees', formData, {
        headers: { 'Content-Type': 'multipart/form-data' },
      })) as AxiosResponse<ImportResponse>;

      return response.data;
    } catch (error) {
      if (axios.isAxiosError(error) && error.response) {
        return rejectWithValue(error.response.data as ServerErrorResponse);
      }
      throw error;
    }
  },
);

export const executeHRImport = createAsyncThunk(
  HRImportsActions.EXECUTE_IMPORT,
  async (
    payload: {
      tempFilePath: string;
      columnMapping: Record<string, string | null>;
      headerRow?: number;
    },
    { rejectWithValue },
  ) => {
    try {
      const response = (await apiPost('/hr/import/employees', {
        temp_file_path: payload.tempFilePath,
        column_mapping: payload.columnMapping,
        header_row: payload.headerRow ?? 1,
      })) as AxiosResponse<ImportBatchResponse>;

      return response.data;
    } catch (error) {
      if (axios.isAxiosError(error) && error.response) {
        return rejectWithValue(error.response.data as ServerErrorResponse);
      }
      throw error;
    }
  },
);

export const fetchImportStatus = createAsyncThunk(
  HRImportsActions.FETCH_IMPORT_STATUS,
  async (batchId: string, { rejectWithValue }) => {
    try {
      const response = (await apiGet(
        `/hr/import/employees/${batchId}/status`,
      )) as AxiosResponse<ImportBatchStatus>;

      return response.data;
    } catch (error) {
      if (axios.isAxiosError(error) && error.response) {
        return rejectWithValue(error.response.data as ServerErrorResponse);
      }
      throw error;
    }
  },
);

export const downloadHRImportTemplate = createAsyncThunk(
  HRImportsActions.DOWNLOAD_TEMPLATE,
  async (_, { rejectWithValue }) => {
    try {
      const response = await apiDownloadBlob('/hr/import/employees/template');
      const filename = resolveFilename(
        response.headers['content-disposition'],
        'hr_employee_import_template.xlsx',
      );
      downloadBlob(new Blob([response.data]), filename);
      return true;
    } catch (error) {
      if (axios.isAxiosError(error) && error.response) {
        return rejectWithValue(error.response.data as ServerErrorResponse);
      }
      throw error;
    }
  },
);

export type HRFixedImportType = 'qualifications' | 'leave-balances';

export const validateFixedImport = createAsyncThunk(
  HRImportsActions.VALIDATE_FIXED_IMPORT,
  async (
    payload: { type: HRFixedImportType; file: File; year?: number },
    { rejectWithValue },
  ) => {
    try {
      const formData = new FormData();
      formData.append('file', payload.file);
      formData.append('validate_only', '1');
      if (payload.year) {
        formData.append('year', String(payload.year));
      }

      const response = (await apiPost(`/hr/import/${payload.type}`, formData, {
        headers: { 'Content-Type': 'multipart/form-data' },
      })) as AxiosResponse<ImportResponse>;

      return response.data;
    } catch (error) {
      if (axios.isAxiosError(error) && error.response) {
        return rejectWithValue(error.response.data as ServerErrorResponse);
      }
      throw error;
    }
  },
);

export const executeFixedImport = createAsyncThunk(
  HRImportsActions.EXECUTE_FIXED_IMPORT,
  async (
    payload: { type: HRFixedImportType; file: File; year?: number },
    { rejectWithValue },
  ) => {
    try {
      const formData = new FormData();
      formData.append('file', payload.file);
      if (payload.year) {
        formData.append('year', String(payload.year));
      }

      const response = (await apiPost(`/hr/import/${payload.type}`, formData, {
        headers: { 'Content-Type': 'multipart/form-data' },
      })) as AxiosResponse<ImportBatchResponse>;

      return { ...response.data, importType: payload.type };
    } catch (error) {
      if (axios.isAxiosError(error) && error.response) {
        return rejectWithValue(error.response.data as ServerErrorResponse);
      }
      throw error;
    }
  },
);

export const fetchFixedImportStatus = createAsyncThunk(
  HRImportsActions.FETCH_FIXED_IMPORT_STATUS,
  async (payload: { type: HRFixedImportType; batchId: string }, { rejectWithValue }) => {
    try {
      const response = (await apiGet(
        `/hr/import/${payload.type}/${payload.batchId}/status`,
      )) as AxiosResponse<ImportBatchStatus>;

      return response.data;
    } catch (error) {
      if (axios.isAxiosError(error) && error.response) {
        return rejectWithValue(error.response.data as ServerErrorResponse);
      }
      throw error;
    }
  },
);

export const downloadFixedTemplate = createAsyncThunk(
  HRImportsActions.DOWNLOAD_FIXED_TEMPLATE,
  async (type: HRFixedImportType, { rejectWithValue }) => {
    try {
      const response = await apiDownloadBlob(`/hr/import/${type}/template`);
      const filename = resolveFilename(
        response.headers['content-disposition'],
        `hr_${type}_import_template.xlsx`,
      );
      downloadBlob(new Blob([response.data]), filename);
      return true;
    } catch (error) {
      if (axios.isAxiosError(error) && error.response) {
        return rejectWithValue(error.response.data as ServerErrorResponse);
      }
      throw error;
    }
  },
);

export const downloadHRImportFailedRows = createAsyncThunk(
  HRImportsActions.DOWNLOAD_FAILED_ROWS,
  async (downloadUrl: string, { rejectWithValue }) => {
    try {
      const response = await axiosInstance.get(downloadUrl, { responseType: 'blob' });
      const filename = resolveFilename(
        response.headers['content-disposition'],
        'hr_import_failed_rows.xlsx',
      );
      downloadBlob(new Blob([response.data]), filename);
      return true;
    } catch (error) {
      if (axios.isAxiosError(error) && error.response) {
        try {
          const text = await (error.response.data as Blob).text();
          return rejectWithValue(JSON.parse(text) as ServerErrorResponse);
        } catch {
          return rejectWithValue({ message: 'Download failed. Please try again.' } as ServerErrorResponse);
        }
      }
      throw error;
    }
  },
);

export const validateIDCardImport = createAsyncThunk(
  HRImportsActions.VALIDATE_ID_CARD_IMPORT,
  async (payload: { file: File; images: File }, { rejectWithValue }) => {
    try {
      const formData = new FormData();
      formData.append('file', payload.file);
      formData.append('images', payload.images);

      const response = (await apiPost('/hr/import/id-cards/validate', formData, {
        headers: { 'Content-Type': 'multipart/form-data' },
      })) as AxiosResponse<IDCardValidationResponse>;

      return response.data;
    } catch (error) {
      if (axios.isAxiosError(error) && error.response) {
        return rejectWithValue(error.response.data as ServerErrorResponse);
      }
      throw error;
    }
  },
);

export const executeIDCardImport = createAsyncThunk(
  HRImportsActions.EXECUTE_ID_CARD_IMPORT,
  async (
    payload: { tempFilePath: string; tempImagesPath: string },
    { rejectWithValue },
  ) => {
    try {
      const response = (await apiPost('/hr/import/id-cards', {
        temp_file_path: payload.tempFilePath,
        temp_images_path: payload.tempImagesPath,
      })) as AxiosResponse<ImportBatchResponse>;

      return response.data;
    } catch (error) {
      if (axios.isAxiosError(error) && error.response) {
        return rejectWithValue(error.response.data as ServerErrorResponse);
      }
      throw error;
    }
  },
);

export const fetchIDCardImportStatus = createAsyncThunk(
  HRImportsActions.FETCH_ID_CARD_IMPORT_STATUS,
  async (batchId: string, { rejectWithValue }) => {
    try {
      const response = (await apiGet(
        `/hr/import/id-cards/${batchId}/status`,
      )) as AxiosResponse<ImportBatchStatus>;

      return response.data;
    } catch (error) {
      if (axios.isAxiosError(error) && error.response) {
        return rejectWithValue(error.response.data as ServerErrorResponse);
      }
      throw error;
    }
  },
);

export const downloadIDCardTemplate = createAsyncThunk(
  HRImportsActions.DOWNLOAD_ID_CARD_TEMPLATE,
  async (_, { rejectWithValue }) => {
    try {
      const response = await apiDownloadBlob('/hr/import/id-cards/template');
      const filename = resolveFilename(
        response.headers['content-disposition'],
        'id_card_import_template.xlsx',
      );
      downloadBlob(new Blob([response.data]), filename);
      return true;
    } catch (error) {
      if (axios.isAxiosError(error) && error.response) {
        return rejectWithValue(error.response.data as ServerErrorResponse);
      }
      throw error;
    }
  },
);

export const HRImportsSlice = createSlice({
  name: 'hrImports',
  initialState,
  reducers: {
    setColumnMapping(state, action: PayloadAction<Record<string, string | null>>) {
      state.columnMapping = action.payload;
    },
    updateColumnMapping(
      state,
      action: PayloadAction<{ header: string; field: string | null }>,
    ) {
      state.columnMapping[action.payload.header] = action.payload.field;
    },
    clearImportState(state) {
      state.previewData = null;
      state.columnMapping = {};
      state.validationResult = null;
      state.importResult = null;
      state.importBatch = null;
      state.idCardTempFilePath = null;
      state.idCardTempImagesPath = null;
      state.error = null;
    },
  },
  extraReducers(builder) {
    builder
      .addCase(previewImportFile.pending, (state: Draft<HRImportsState>) => {
        state.previewing = true;
        state.error = null;
      })
      .addCase(
        previewImportFile.fulfilled,
        (state: Draft<HRImportsState>, action: PayloadAction<PreviewResponse>) => {
          state.previewing = false;
          state.previewData = action.payload;
          state.columnMapping = action.payload.suggested_mapping;
        },
      )
      .addCase(
        previewImportFile.rejected,
        (state: Draft<HRImportsState>, action: RejectedActionPayload) => {
          state.previewing = false;
          state.error = Helpers.handleServerError(action.payload);
          message.error(state.error, 10);
        },
      );

    builder
      .addCase(validateHRImport.pending, (state: Draft<HRImportsState>) => {
        state.validating = true;
        state.error = null;
      })
      .addCase(
        validateHRImport.fulfilled,
        (state: Draft<HRImportsState>, action: PayloadAction<ImportResponse>) => {
          state.validating = false;
          state.validationResult = action.payload;
          message.success(action.payload.message || 'Validation completed successfully');
        },
      )
      .addCase(
        validateHRImport.rejected,
        (state: Draft<HRImportsState>, action: RejectedActionPayload) => {
          state.validating = false;
          state.error = Helpers.handleServerError(action.payload);
          message.error(state.error, 10);
        },
      );

    builder
      .addCase(executeHRImport.pending, (state: Draft<HRImportsState>) => {
        state.importing = true;
        state.error = null;
      })
      .addCase(
        executeHRImport.fulfilled,
        (state: Draft<HRImportsState>, 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');
        },
      )
      .addCase(
        executeHRImport.rejected,
        (state: Draft<HRImportsState>, action: RejectedActionPayload) => {
          state.importing = false;
          state.error = Helpers.handleServerError(action.payload);
          message.error(state.error, 10);
        },
      );

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

          if (action.payload.finished) {
            state.importResult = {
              message: 'Import completed successfully.',
              validate_only: false,
              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_file: null,
              failed_rows_download_url: action.payload.failed_rows_download_url ?? null,
            };
          }
        },
      );

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

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

    builder
      .addCase(validateFixedImport.pending, (state: Draft<HRImportsState>) => {
        state.validating = true;
        state.error = null;
      })
      .addCase(
        validateFixedImport.fulfilled,
        (state: Draft<HRImportsState>, action: PayloadAction<ImportResponse>) => {
          state.validating = false;
          state.validationResult = action.payload;
          message.success(action.payload.message || 'Validation completed successfully');
        },
      )
      .addCase(
        validateFixedImport.rejected,
        (state: Draft<HRImportsState>, action: RejectedActionPayload) => {
          state.validating = false;
          state.error = Helpers.handleServerError(action.payload);
          message.error(state.error, 10);
        },
      );

    builder
      .addCase(executeFixedImport.pending, (state: Draft<HRImportsState>) => {
        state.importing = true;
        state.error = null;
      })
      .addCase(
        executeFixedImport.fulfilled,
        (state: Draft<HRImportsState>, action: PayloadAction<ImportBatchResponse & { importType: HRFixedImportType }>) => {
          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 started. Processing in background...');
        },
      )
      .addCase(
        executeFixedImport.rejected,
        (state: Draft<HRImportsState>, action: RejectedActionPayload) => {
          state.importing = false;
          state.error = Helpers.handleServerError(action.payload);
          message.error(state.error, 10);
        },
      );

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

          if (action.payload.finished) {
            state.importResult = {
              message: 'Import completed successfully.',
              validate_only: false,
              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_file: null,
              failed_rows_download_url: action.payload.failed_rows_download_url ?? null,
            };
          }
        },
      )
      .addCase(
        fetchFixedImportStatus.rejected,
        (state: Draft<HRImportsState>, action: RejectedActionPayload) => {
          state.error = Helpers.handleServerError(action.payload);
        },
      );

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

    builder
      .addCase(validateIDCardImport.pending, (state: Draft<HRImportsState>) => {
        state.validating = true;
        state.error = null;
      })
      .addCase(
        validateIDCardImport.fulfilled,
        (state: Draft<HRImportsState>, action: PayloadAction<IDCardValidationResponse>) => {
          state.validating = false;
          state.validationResult = action.payload;
          state.idCardTempFilePath = action.payload.temp_file_path;
          state.idCardTempImagesPath = action.payload.temp_images_path;
          message.success(action.payload.message || 'Validation completed successfully');
        },
      )
      .addCase(
        validateIDCardImport.rejected,
        (state: Draft<HRImportsState>, action: RejectedActionPayload) => {
          state.validating = false;
          state.error = Helpers.handleServerError(action.payload);
          message.error(state.error, 10);
        },
      );

    builder
      .addCase(executeIDCardImport.pending, (state: Draft<HRImportsState>) => {
        state.importing = true;
        state.error = null;
      })
      .addCase(
        executeIDCardImport.fulfilled,
        (state: Draft<HRImportsState>, 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 started. Processing in background...');
        },
      )
      .addCase(
        executeIDCardImport.rejected,
        (state: Draft<HRImportsState>, action: RejectedActionPayload) => {
          state.importing = false;
          state.error = Helpers.handleServerError(action.payload);
          message.error(state.error, 10);
        },
      );

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

          if (action.payload.finished) {
            state.importResult = {
              message: 'Import completed successfully.',
              validate_only: false,
              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_file: null,
              failed_rows_download_url: action.payload.failed_rows_download_url ?? null,
            };
          }
        },
      )
      .addCase(
        fetchIDCardImportStatus.rejected,
        (state: Draft<HRImportsState>, action: RejectedActionPayload) => {
          state.error = Helpers.handleServerError(action.payload);
        },
      );

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

export const { setColumnMapping, updateColumnMapping, clearImportState } =
  HRImportsSlice.actions;

export default HRImportsSlice;
