import { z } from 'zod';
import dayjs from 'dayjs';

const today = dayjs();
const minDate =
  today.date() >= 21 ? today.startOf('month') : today.subtract(1, 'month').startOf('month');
const maxDate = today;
const maxKeterangan = 5;

export const FakturPkSchema = z
  .object({
    fgUangMuka: z.string().nonempty('Tipe pembayaran harus diisi'),
    detailTransaksi: z.string().nonempty('Kode transaksi harus diisi'),

    refDoc: z.string().optional(),
    idKeteranganTambahan: z.string().optional(),
    fgPengganti: z.string().default('0'),

    nomorFaktur: z.string().optional(),

    idLainPembeli: z.string().nonempty('Identitas wajib diisi'),

    tanggalFaktur: z
      .string()
      .nonempty('Tanggal faktur harus diisi')
      .refine(
        (val) => {
          const date = dayjs(val);
          return (
            date.isValid() &&
            date.isAfter(minDate.subtract(1, 'day')) &&
            date.isBefore(maxDate.add(1, 'day'))
          );
        },
        {
          message: `Tanggal faktur harus antara ${minDate.format('YYYY-MM-DD')} dan ${maxDate.format(
            'YYYY-MM-DD'
          )}`,
        }
      ),

    masaTahunPajak: z.string().nonempty('Masa/Tahun Pajak harus diisi'),

    referensi: z.string().optional(),
    keterangan1: z.string().optional(),
    keterangan2: z.string().optional(),
    keterangan3: z.string().optional(),
    keterangan4: z.string().optional(),
    keterangan5: z.string().optional(),

    ...Object.fromEntries(
      Array.from({ length: maxKeterangan }).map((_, i) => [
        `keterangan${i + 1}`,
        z.string().optional(),
      ])
    ),

    npwpPembeli: z.string().optional(),
    namaPembeli: z.string().nonempty('Nama Pembeli wajib diisi'),
    // kdNegaraPembeli: z.string().nonempty('Kode Negara wajib diisi'),
    kdNegaraPembeli: z.string().min(1, 'Kode Negara wajib diisi'),
    tkuPembeli: z.string().nonempty('TKU Pembeli wajib diisi'),
    emailPembeli: z.string().optional(),
    alamatPembeli: z.string().nonempty('Alamat wajib diisi'),

    objekFaktur: z.array(z.any()).optional(),

    totalJumlahBarang: z
      .union([z.string(), z.number()])
      .transform((v) => Number(v) || 0)
      .optional(),
    totalHarga: z
      .union([z.string(), z.number()])
      .transform((v) => Number(v) || 0)
      .optional(),
    totalDiskon: z
      .union([z.string(), z.number()])
      .transform((v) => Number(v) || 0)
      .optional(),
    totalDpp: z
      .union([z.string(), z.number()])
      .transform((v) => Number(v) || 0)
      .optional(),
    totalDppLain: z
      .union([z.string(), z.number()])
      .transform((v) => Number(v) || 0)
      .optional(),
    totalPpn: z
      .union([z.string(), z.number()])
      .transform((v) => Number(v) || 0)
      .optional(),
    totalPpnbm: z
      .union([z.string(), z.number()])
      .transform((v) => Number(v) || 0)
      .optional(),

    jumlahUangMuka: z.union([z.string(), z.number()]).optional(),
    uangMukaDpp: z.union([z.string(), z.number()]).optional(),
    sisaPelunasan: z.union([z.string(), z.number()]).optional(),
    approvalSign: z.string().nonempty('NPWP/NIK Penandatangan wajib diisi'),
  })

  // WAJIB nomorFaktur jika pelunasan dan faktur normal
  .refine(
    (data) => {
      if (data.fgUangMuka === 'pelunasan' && data.fgPengganti === '0') {
        return data.nomorFaktur && data.nomorFaktur.trim() !== '';
      }
      return true;
    },
    {
      message: 'Nomor Seri Faktur wajib diisi',
      path: ['nomorFaktur'],
    }
  )

  // ===================== SUPER REFINE =========================
  .superRefine((data, ctx) => {
    const parseNumOrNull = (v: unknown) => {
      if (v === undefined || v === null) return null;
      if (typeof v === 'string' && v.trim() === '') return null;
      const n = Number(String(v).replace(/[^0-9.-]/g, ''));
      return Number.isFinite(n) ? n : null;
    };

    const sisa = parseNumOrNull(data.sisaPelunasan) ?? 0;

    // =========== VALIDASI IDENTITAS ===========
    if (data.idLainPembeli === '0') {
      if (!data.npwpPembeli || !/^\d{16}$/.test(data.npwpPembeli)) {
        ctx.addIssue({
          path: ['npwpPembeli'],
          code: 'custom',
          message: 'NPWP Pembeli harus 16 digit ',
        });
      }
    }

    if (data.idLainPembeli === '1') {
      if (!data.npwpPembeli || !/^\d{16}$/.test(data.npwpPembeli)) {
        ctx.addIssue({
          path: ['npwpPembeli'],
          code: 'custom',
          message: 'NIK Pembeli harus 16 digit',
        });
      }
    }

    if (data.idLainPembeli === '2') {
      if (!data.npwpPembeli || data.npwpPembeli.trim() === '') {
        ctx.addIssue({
          path: ['npwpPembeli'],
          code: 'custom',
          message: 'Passport Pembeli wajib diisi',
        });
      }
    }

    if (data.idLainPembeli === '3') {
      if (!data.npwpPembeli || data.npwpPembeli.trim() === '') {
        ctx.addIssue({
          path: ['npwpPembeli'],
          code: 'custom',
          message: 'ID Lain Pembeli wajib diisi',
        });
      }
    }

    // ======================================================
    // =============== UANG MUKA / PELUNASAN RULES ==========
    // ======================================================

    // ========== UANG MUKA (UM lanjutan / UM pertama) ============
    if (data.fgUangMuka === 'uang_muka') {
      const j = parseNumOrNull(data.jumlahUangMuka);
      const totalDppLain = parseNumOrNull(data.totalDppLain);

      // valid (17 digit)
      const nomorValid = data.nomorFaktur && data.nomorFaktur.length === 17;

      // ---------- UM Lanjutan (nomorFaktur valid) ----------
      if (nomorValid) {
        if (j === null) {
          ctx.addIssue({
            path: ['jumlahUangMuka'],
            code: 'custom',
            message: 'Jumlah Uang Muka wajib diisi.',
          });
        } else if (j > sisa) {
          ctx.addIssue({
            path: ['jumlahUangMuka'],
            code: 'custom',
            message: `Jumlah Uang Muka tidak boleh lebih dari Sisa Pelunasan (${new Intl.NumberFormat(
              'id-ID'
            ).format(sisa)}).`,
          });
        }
      }

      // ---------- UM Pertama (nomorFaktur tidak valid) ----------
      if (!nomorValid) {
        if (j === null || j < 1) {
          ctx.addIssue({
            path: ['jumlahUangMuka'],
            code: 'custom',
            message: 'Jumlah Uang Muka minimal 1 untuk Uang Muka pertama.',
          });
        }

        if (totalDppLain != null && j != null && j >= totalDppLain) {
          ctx.addIssue({
            path: ['jumlahUangMuka'],
            code: 'custom',
            message: `Jumlah Uang Muka harus lebih kecil dari Total DPP Lain (${new Intl.NumberFormat(
              'id-ID'
            ).format(totalDppLain)}).`,
          });
        }
      }
    }

    // =================== PELUNASAN ======================
    if (data.fgUangMuka === 'pelunasan') {
      const val = parseNumOrNull(data.uangMukaDpp);

      if (val === null) {
        ctx.addIssue({
          path: ['uangMukaDpp'],
          code: 'custom',
          message: 'Nilai Pelunasan wajib diisi.',
        });
      } else if (val !== sisa) {
        ctx.addIssue({
          path: ['uangMukaDpp'],
          code: 'custom',
          message: `Pelunasan harus sama persis dengan Sisa Pelunasan (${new Intl.NumberFormat(
            'id-ID'
          ).format(sisa)}).`,
        });
      }
    }

    if (!data.kdNegaraPembeli || data.kdNegaraPembeli.trim() === '') {
      ctx.addIssue({
        path: ['kdNegaraPembeli'],
        code: 'custom',
        message: 'Kode negara pembeli tidak boleh kosong',
      });
    }
  });

export type TFakturPkSchema = z.infer<typeof FakturPkSchema>;
