import {
  IndividualLeaveReport,
  LeavePlanFilters,
  LeavePlanReport,
  LeaveReportExportPayload,
  LeaveSummaryFilters,
  LeaveSummaryReport,
  OnLeaveEmployee,
  OnLeaveFilters,
} from '@/interface/LeaveReport';
import { RejectedActionPayload, ServerErrorResponse } from '@/interface/Shared';
import { 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 { LeaveReportActions } from './actionTypes';

interface LeaveReportsState {
  onLeaveEmployees: OnLeaveEmployee[];
  onLeaveDate: string | null;
  summaryReport: LeaveSummaryReport | null;
  individualReport: IndividualLeaveReport | null;
  leavePlan: LeavePlanReport | null;
  loading: boolean;
  exportLoading: boolean;
  error: string | null;
}

const initialState: LeaveReportsState = {
  onLeaveEmployees: [],
  onLeaveDate: null,
  summaryReport: null,
  individualReport: null,
  leavePlan: null,
  loading: false,
  exportLoading: false,
  error: null,
};

const buildQueryString = (params: Record<string, unknown>): string => {
  const searchParams = new URLSearchParams();

  Object.entries(params).forEach(([key, value]) => {
    if (value !== undefined && value !== null && value !== '') {
      searchParams.append(key, String(value));
    }
  });

  const qs = searchParams.toString();
  return qs ? `?${qs}` : '';
};

export const fetchOnLeave = createAsyncThunk(
  LeaveReportActions.FETCH_ON_LEAVE,
  async (filters: OnLeaveFilters = {}, { rejectWithValue }) => {
    try {
      const qs = buildQueryString(filters as Record<string, unknown>);
      const response = (await apiGet(`/leave/reports/on-leave${qs}`)) as AxiosResponse<{
        date: string;
        data: OnLeaveEmployee[];
      }>;
      return response.data;
    } catch (error) {
      if (axios.isAxiosError(error) && error.response) {
        return rejectWithValue(error.response.data as ServerErrorResponse);
      }
      throw error;
    }
  },
);

export const fetchSummaryReport = createAsyncThunk(
  LeaveReportActions.FETCH_SUMMARY,
  async (filters: LeaveSummaryFilters = {}, { rejectWithValue }) => {
    try {
      const qs = buildQueryString(filters as Record<string, unknown>);
      const response = (await apiGet(`/leave/reports/summary${qs}`)) as AxiosResponse<LeaveSummaryReport>;
      return response.data;
    } catch (error) {
      if (axios.isAxiosError(error) && error.response) {
        return rejectWithValue(error.response.data as ServerErrorResponse);
      }
      throw error;
    }
  },
);

export const fetchIndividualReport = createAsyncThunk(
  LeaveReportActions.FETCH_INDIVIDUAL,
  async (params: { employeeId: string; year?: number }, { rejectWithValue }) => {
    try {
      const qs = params.year ? `?year=${params.year}` : '';
      const response = (await apiGet(
        `/leave/reports/individual/${params.employeeId}${qs}`,
      )) as AxiosResponse<IndividualLeaveReport>;
      return response.data;
    } catch (error) {
      if (axios.isAxiosError(error) && error.response) {
        return rejectWithValue(error.response.data as ServerErrorResponse);
      }
      throw error;
    }
  },
);

export const fetchLeavePlan = createAsyncThunk(
  LeaveReportActions.FETCH_LEAVE_PLAN,
  async (filters: LeavePlanFilters = {}, { rejectWithValue }) => {
    try {
      const qs = buildQueryString(filters as Record<string, unknown>);
      const response = (await apiGet(`/leave/reports/leave-plan${qs}`)) as AxiosResponse<LeavePlanReport>;
      return response.data;
    } catch (error) {
      if (axios.isAxiosError(error) && error.response) {
        return rejectWithValue(error.response.data as ServerErrorResponse);
      }
      throw error;
    }
  },
);

const resolveFilename = (contentDisposition: string | undefined, fallback: string): 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 exportReport = createAsyncThunk(
  LeaveReportActions.EXPORT_REPORT,
  async (payload: LeaveReportExportPayload, { rejectWithValue }) => {
    try {
      const response = await axiosInstance.post('/leave/reports/export', payload, {
        responseType: 'blob',
      });
      const fallbackName = `leave_${payload.report_type}_report.${payload.format}`;
      const filename = resolveFilename(response.headers['content-disposition'], fallbackName);
      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 LeaveReportsSlice = createSlice({
  name: 'leaveReports',
  initialState,
  reducers: {
    clearIndividualReport(state) {
      state.individualReport = null;
    },
  },
  extraReducers(builder) {
    builder
      .addCase(fetchOnLeave.pending, (state: Draft<LeaveReportsState>) => {
        state.loading = true;
        state.error = null;
      })
      .addCase(
        fetchOnLeave.fulfilled,
        (state: Draft<LeaveReportsState>, action: PayloadAction<{ date: string; data: OnLeaveEmployee[] }>) => {
          state.loading = false;
          state.onLeaveEmployees = action.payload.data;
          state.onLeaveDate = action.payload.date;
        },
      )
      .addCase(fetchOnLeave.rejected, (state: Draft<LeaveReportsState>, action: RejectedActionPayload) => {
        state.loading = false;
        state.error = Helpers.handleServerError(action.payload);
        message.error(state.error, 10);
      })

      .addCase(fetchSummaryReport.pending, (state: Draft<LeaveReportsState>) => {
        state.loading = true;
        state.error = null;
      })
      .addCase(
        fetchSummaryReport.fulfilled,
        (state: Draft<LeaveReportsState>, action: PayloadAction<LeaveSummaryReport>) => {
          state.loading = false;
          state.summaryReport = action.payload;
        },
      )
      .addCase(fetchSummaryReport.rejected, (state: Draft<LeaveReportsState>, action: RejectedActionPayload) => {
        state.loading = false;
        state.error = Helpers.handleServerError(action.payload);
        message.error(state.error, 10);
      })

      .addCase(fetchIndividualReport.pending, (state: Draft<LeaveReportsState>) => {
        state.loading = true;
        state.error = null;
      })
      .addCase(
        fetchIndividualReport.fulfilled,
        (state: Draft<LeaveReportsState>, action: PayloadAction<IndividualLeaveReport>) => {
          state.loading = false;
          state.individualReport = action.payload;
        },
      )
      .addCase(fetchIndividualReport.rejected, (state: Draft<LeaveReportsState>, action: RejectedActionPayload) => {
        state.loading = false;
        state.error = Helpers.handleServerError(action.payload);
        message.error(state.error, 10);
      })

      .addCase(fetchLeavePlan.pending, (state: Draft<LeaveReportsState>) => {
        state.loading = true;
        state.error = null;
      })
      .addCase(
        fetchLeavePlan.fulfilled,
        (state: Draft<LeaveReportsState>, action: PayloadAction<LeavePlanReport>) => {
          state.loading = false;
          state.leavePlan = action.payload;
        },
      )
      .addCase(fetchLeavePlan.rejected, (state: Draft<LeaveReportsState>, action: RejectedActionPayload) => {
        state.loading = false;
        state.error = Helpers.handleServerError(action.payload);
        message.error(state.error, 10);
      })

      .addCase(exportReport.pending, (state: Draft<LeaveReportsState>) => {
        state.exportLoading = true;
      })
      .addCase(exportReport.fulfilled, (state: Draft<LeaveReportsState>) => {
        state.exportLoading = false;
        message.success('Report exported successfully');
      })
      .addCase(exportReport.rejected, (state: Draft<LeaveReportsState>, action: RejectedActionPayload) => {
        state.exportLoading = false;
        const errorMessage = Helpers.handleServerError(action.payload);
        message.error(errorMessage, 10);
      });
  },
});

export const { clearIndividualReport } = LeaveReportsSlice.actions;
export default LeaveReportsSlice;
export type { LeaveReportsState };
