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 { FG_PERHITUNGAN, PERHITUNGAN_BUPOT21, PTKP_NUMBER } from './constant';
import { checkPerhitunganBupot21, type paramsHitung } from './helper';
import { formatDate } from './bupot-a1/utils/formatDate';

// ========================================
// 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'
>;

export type transformParamsTahunanA1Props = {
  kdObjPjk: string;
  npwp: string;
  thnPajak: string;
  msPjkAwal: string;
  msPjkAkhir: string;
  metode: string;
  statusPtkp: string;
  fgFasilitas: string;
  metodePemotongan: string;

  rincian1: string;
  rincian2: string;
  rincian3: string;
  rincian4: string;
  rincian5: string;
  rincian6: string;
  rincian7: string;

  rincian9: string;
  rincian10: string;
  rincian11: string;

  rincian14: string;
  rincian20: string;
  rincian22: string;
};

interface ApiResponseTahunanA1 {
  code: 1 | 0;
  message: null;
  gajiPensiun1: string;
  tunjPph2: string;
  tunjLain3: string;
  honorarium4: string;
  premiAsuransi5: string;
  natura6: string;
  bonus7: string;
  jmlBruto8: string;
  biayaJabatan9: string;
  iuranPensiun10: string;
  zakat11: string;
  jmlPengurang12: string;
  jmlNeto13: string;
  netoSebelumnya14: string;
  netoSetahunDisetahunkan15: string;
  ptkp16: string;
  pkpSetahun17: string;
  pph21Pkp18: string;
  pph21Terhutang19: string;
  pph21Sebelumnya20: string;
  pph21Dikreditkan21: string;
  pph21DtpSebelumnya22: string;
  pph21KurangLebih23: string;
  dblPPh21SetahunDitanggungPerusahaan: string;
  dblPPh21SetahunDitanggungKaryawan: string;
  dbNetoSetahunREGULERONLY: string;
  dbPKPREGULERONLY: string;
  dbPPH21ATASPKPREGULERONLY: string;
  dbPPh21SetahunREGONLY: string;
  dbPPh21SetahunIREG: string;
  pph21Terutang21: string;
  pph21SelainMpt22Aperusahaan: null | string;
  pph21SelainMpt22Akaryawan: null | string;
  pph2123Aperusahaan: null | string;
  pph2123Akaryawan: null | string;
}

type MutationTahunanA1Props<T> = Omit<
  UseMutationOptions<ApiResponseTahunanA1, 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: stringN_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',
});

const transformParamsTahunanA1 = (params: any) => {
  const [ptkpKey, kdPtkp] = params.statusPtkp.value.split('/') as [keyof typeof PTKP_NUMBER, string];

  console.log("🚀 ~ transformParamsTahunanA1:", {params, ptkpKey});
  if (!kdPtkp) {
    throw new Error('Format status tidak valid. Expected: stringN_TANGGUNGAN"');
  }

  return {
    kdObjPjk: params.kdObjPjk.value,
    npwp: params.npwp,
    thnPajak: params.tahunPajak,
    msPjkAwal: formatDate(params.masaPajakAwal, 'M'),
    msPjkAkhir: formatDate(params.masaPajakAkhir, 'M'),
    metode: params.fgPerhitungan === FG_PERHITUNGAN.GROSS ? 'gross' : 'gross-up',
    jmlTanggungan: PTKP_NUMBER[ptkpKey],
    kdPtkp,
    fgDisetahunkan15: params.metodePemotongan !== '3' ? 0 : 1,
    msPajak1: formatDate(params.masaPajakAwal, 'M'),
    msPajak2: formatDate(params.masaPajakAkhir, 'M'),

    // PENGHASILAN
    gajiPensiun1: params.rincian1,
    tunjPph2: params.rincian2,
    tunjLain3: params.rincian3,
    honorarium4: params.rincian4,
    premiAsuransi5: params.rincian5,
    natura6: params.rincian6,
    bonus7: params.rincian7,

    // PENGURANGAN
    biayaJabatan9: params.rincian9,
    iuranPensiun10: params.rincian10 || '0',
    zakat11: params.rincian11,

    // PH dan NETO SEBELUMNYA
    netoSebelumnya14: params.rincian14,
    pph21Sebelumnya20: params.rincian20,
    pph21DtpSebelumnya22: params.rincian22,
  };
};

const normalizeResponseTahunanA1 = (params: ApiResponseTahunanA1) => {
  console.log('normalizeResponseTahunanA1 = ', { params });

  return {
    rincian2: params.tunjPph2 || '0',
    rincian8: params.jmlBruto8,
    rincian9: params.biayaJabatan9,
    rincian10: params.iuranPensiun10,
    rincian11: params.zakat11,
    rincian12: params.jmlPengurang12,
    rincian13: params.jmlNeto13,
    rincian14: params.netoSebelumnya14,
    rincian15: Math.round(Number(params.netoSetahunDisetahunkan15)),
    rincian16: params.ptkp16,
    rincian17: params.pkpSetahun17,
    rincian18: params.pph21Pkp18,
    rincian19: params.pph21Terhutang19,
    rincian20: params.pph21Sebelumnya20 || '0',
    rincian21: params.pph21Dikreditkan21,
    rincian22: params.pph21DtpSebelumnya22,
    rincian23: params.pph21KurangLebih23,

    // Additional calculations
    // pph21DitanggungPerusahaan: params.dblPPh21SetahunDitanggungPerusahaan,
    // pph21DitanggungKaryawan: params.dblPPh21SetahunDitanggungKaryawan,

    // Regular calculations
    // netoSetahunRegulerOnly: params.dbNetoSetahunREGULERONLY,
    // pkpRegulerOnly: params.dbPKPREGULERONLY,
    // pph21AtasPkpRegulerOnly: params.dbPPH21ATASPKPREGULERONLY,
    // pph21SetahunRegulerOnly: params.dbPPh21SetahunREGONLY,
    // pph21SetahunIreguler: params.dbPPh21SetahunIREG,

    // PPh21 calculations
    // pph21SelainMptPerusahaan: params.pph21SelainMpt22Aperusahaan,
    // pph21SelainMptKaryawan: params.pph21SelainMpt22Akaryawan,
    // pph2123Perusahaan: params.pph2123Aperusahaan,
    // pph2123Karyawan: params.pph2123Akaryawan,
    // pph2123: params.pph2123Akaryawan,
    // pph21Dtp: params.pph21DtpSebelumnya22,
  };
};

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

const { bulanan, harian, pasal17, pensiun, pesangon, tahunan } = 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> => {
  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}`
      );
  }
};

const hitungTahunanA1 = async (params: transformParamsTahunanA1Props) => {
  const response = await fetcherHitung<ApiResponseTahunanA1>([
    tahunan,
    {
      method: 'POST',
      data: transformParamsTahunanA1(params),
    },
  ]);

  return normalizeResponseTahunanA1(response);
};

// ========================================
// 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,
  });
}

export function useHitungTahunanA1(
  props?: MutationTahunanA1Props<transformParamsTahunanA1Props>
): UseMutationResult<ApiResponseTahunanA1, AxiosError, transformParamsTahunanA1Props> {
  return useMutation({
    mutationKey: ['pph-21-26', 'tahunan-a1', 'hitung'],
    mutationFn: hitungTahunanA1 as any,
    ...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';
};
