import {
  useMutation,
  type UseMutationOptions,
  type UseMutationResult,
} from '@tanstack/react-query';
import type { AxiosError } from 'axios';
import { endpoints, fetcherHitung } from 'src/lib/axios-ctas-box';
import { PERHITUNGAN_BUPOT21 } from './constant';
import { checkPerhitunganBupot21, type paramsHitung } from './helper';

// ========================================
// Types
// ========================================

export type transformParamsBupotBulananProps = {
  status: string;
  metode: 'gross' | 'gross-up';
  tglBupot: string;
  penghasilanKotor: string;
  dppPersen: string;
  jenisHitung: string;
} & paramsHitung;

interface ApiResponse<T> {
  code: number;
  status: string;
  message?: string;
  data: T;
}

interface ApiResponseBulanan {
  nip: string | null;
  tglBupot: string | null;
  metode: string | null;
  status: 'TK' | 'K' | 'HB';
  nTanggungan: 0 | 1 | 2 | 3;
  tunjanganPPh: string;
  penghasilanBruto: string | null;
  tarif: string;
  kelasTer: string;
  pphBulan: string;
  pph21ditanggungperusahaan: string;
  pph21ditanggungkaryawan: string;
  pph21: string;
  pphDipotong: string;
}

interface TransformedBupotParams {
  status: string;
  nTanggungan: string;
  metode: 'gross' | 'gross-up';
  tglBupot: string;
  penghasilanKotor: string | number;
  dpp: string | number;
}

type MutationProps<T> = Omit<
  UseMutationOptions<ApiResponseBulanan, AxiosError, T>,
  'mutationKey' | 'mutationFn'
>;

// ========================================
// Validation & Transform Functions
// ========================================

const validateResponse = <T>(response: ApiResponse<T>): T => {
  const failedStatuses = ['fail', 'error', '0'];

  if (failedStatuses.includes(response.status)) {
    throw new Error(
      response.message || 'System tidak dapat memenuhi permintaan, coba beberapa saat lagi'
    );
  }

  if (!response.data) {
    throw new Error('Data response tidak ditemukan');
  }

  return response.data;
};

const transformParamsBupotBulanan = (
  params: transformParamsBupotBulananProps
): TransformedBupotParams => {
  const [status, nTanggungan] = params.status.split('/');

  if (!status || !nTanggungan) {
    throw new Error('Format status tidak valid. Expected: "STATUS/N_TANGGUNGAN"');
  }

  return {
    status,
    nTanggungan,
    metode: params.metode,
    tglBupot: params.tglBupot,
    penghasilanKotor: params.penghasilanKotor,
    dpp: params.dppPersen,
  };
};

const transformParamsBupotBulananFinalTidakFinal = (params: any) => {
  const splis = params.status?.split('/');
  return {
    status: splis && splis[0],
    nTanggungan: splis && splis[1],
    metode: params.metode, // isi gross atau gross-up
    tglBupot: params.tglBupot, // FORMAT yyyy-MM-dd
    kodeObjekPajak: params.kodeObjekPajak,
    penghasilanKotor: params.penghasilanKotor,
    dpp: params.dppPersen,
    npwp: params.npwp,
    penghasilanKotorSebelumnya: params.akumulasiJmlBruto || 0,
  };
};

const normalizeResponse = (data: ApiResponseBulanan): ApiResponseBulanan => ({
  ...data,
  pph21: data.pph21 || data.pphDipotong || '0',
});

// ========================================
// API Request Handlers
// ========================================

const { bulanan, harian, pasal17, pensiun, pesangon } = endpoints.hitung;

const hitungBulananGross = async (
  params: transformParamsBupotBulananProps
): Promise<ApiResponseBulanan> => {
  const response = await fetcherHitung<ApiResponse<ApiResponseBulanan>>([
    bulanan,
    {
      method: 'POST',
      data: transformParamsBupotBulanan({ ...params, metode: 'gross' }),
    },
  ]);

  return normalizeResponse(validateResponse(response));
};

const hitungBulananGrossUp = async (
  params: transformParamsBupotBulananProps
): Promise<ApiResponseBulanan> => {
  const response = await fetcherHitung<ApiResponse<ApiResponseBulanan>>([
    bulanan,
    {
      method: 'POST',
      data: transformParamsBupotBulanan({ ...params, metode: 'gross-up' }),
    },
  ]);

  return normalizeResponse(validateResponse(response));
};

const hitungHarianTER = async (params: transformParamsBupotBulananProps) => {
  const response = await fetcherHitung<ApiResponse<ApiResponseBulanan>>([
    harian,
    {
      method: 'POST',
      data: transformParamsBupotBulananFinalTidakFinal(params),
    },
  ]);

  return normalizeResponse(validateResponse(response));
};

const hitungPasal17 = async (params: transformParamsBupotBulananProps) => {
  const response = await fetcherHitung<ApiResponse<ApiResponseBulanan>>([
    pasal17,
    {
      method: 'POST',
      data: transformParamsBupotBulananFinalTidakFinal(params),
    },
  ]);

  return normalizeResponse(validateResponse(response));
};

const hitungPensiun = async (params: transformParamsBupotBulananProps) => {
  const response = await fetcherHitung<ApiResponse<ApiResponseBulanan>>([
    pensiun,
    {
      method: 'POST',
      data: transformParamsBupotBulananFinalTidakFinal(params),
    },
  ]);

  return normalizeResponse(validateResponse(response));
};

const hitungPesangon = async (params: transformParamsBupotBulananProps) => {
  const response = await fetcherHitung<ApiResponse<ApiResponseBulanan>>([
    pesangon,
    {
      method: 'POST',
      data: transformParamsBupotBulananFinalTidakFinal(params),
    },
  ]);

  return normalizeResponse(validateResponse(response));
};

const handleHitungBulanan = async (
  params: transformParamsBupotBulananProps
): Promise<ApiResponseBulanan> => {
  const checkPerhitungan = checkPerhitunganBupot21(params);

  switch (checkPerhitungan) {
    case PERHITUNGAN_BUPOT21.BULANAN_GROSS:
      return hitungBulananGross(params);

    case PERHITUNGAN_BUPOT21.BULANAN_GROSS_UP:
      return hitungBulananGrossUp(params);

    default:
      throw new Error(
        `Tipe perhitungan tidak valid: ${checkPerhitungan}. Expected: ${PERHITUNGAN_BUPOT21.BULANAN_GROSS} atau ${PERHITUNGAN_BUPOT21.BULANAN_GROSS_UP}`
      );
  }
};

const handleHitungBupotFinal = async (
  params: transformParamsBupotBulananProps
): Promise<ApiResponseBulanan> => {
  console.log('handleHitungBupotFinal',{params});

  switch (params.jenisHitung) {
    case PERHITUNGAN_BUPOT21.BULANAN:
      return hitungBulananGross(params);

    case PERHITUNGAN_BUPOT21.HARIAN_TER:
      return hitungHarianTER(params);

    case PERHITUNGAN_BUPOT21.PASAL_17:
      return hitungPasal17(params);

    case PERHITUNGAN_BUPOT21.PENSIUN:
      return hitungPensiun(params);

    case PERHITUNGAN_BUPOT21.PESANGON:
      return hitungPesangon(params);

    default:
      throw new Error(
        `Tipe perhitungan tidak valid: ${params.jenisHitung}. Expected: ${PERHITUNGAN_BUPOT21.BULANAN}, ${PERHITUNGAN_BUPOT21.HARIAN_TER}, ${PERHITUNGAN_BUPOT21.PASAL_17}, ${PERHITUNGAN_BUPOT21.PENSIUN}, ${PERHITUNGAN_BUPOT21.PESANGON}`
      );
  }
};

// ========================================
// React Query Hook
// ========================================

export function useHitungBulanan(
  props?: MutationProps<transformParamsBupotBulananProps>
): UseMutationResult<ApiResponseBulanan, AxiosError, transformParamsBupotBulananProps> {
  return useMutation({
    mutationKey: ['pph-21-26', 'bulanan', 'hitung'],
    mutationFn: handleHitungBulanan,
    ...props,
  });
}

export function useHitungBupotFinalTidakFinal(
  props?: MutationProps<transformParamsBupotBulananProps>
): UseMutationResult<ApiResponseBulanan, AxiosError, transformParamsBupotBulananProps> {
  return useMutation({
    mutationKey: ['pph-21-26', 'bupot-final-tidak-final', 'hitung'],
    mutationFn: handleHitungBupotFinal,
    ...props,
  });
}

// ========================================
// Error Handler Utility (Optional)
// ========================================

export const getHitungBulananErrorMessage = (error: unknown): string => {
  if (error instanceof Error) {
    return error.message;
  }

  if (typeof error === 'object' && error !== null && 'response' in error) {
    const axiosError = error as AxiosError<ApiResponse<any>>;
    return (
      axiosError.response?.data?.message ||
      axiosError.message ||
      'Terjadi kesalahan saat menghitung PPh 21'
    );
  }

  return 'Terjadi kesalahan yang tidak diketahui';
};
