import React, { useEffect, useMemo, useState, useRef } from 'react';
import Box from '@mui/material/Box';
import Stack from '@mui/material/Stack';
import Grid from '@mui/material/Grid';
import Divider from '@mui/material/Divider';
import Button from '@mui/material/Button';
import IconButton from '@mui/material/IconButton';
import { Delete, Edit } from '@mui/icons-material';
import { DataGridPremium, useGridApiRef } from '@mui/x-data-grid-premium';
import type { GridColDef } from '@mui/x-data-grid';

import { useFormContext, useWatch } from 'react-hook-form';
import { useParams } from 'react-router';

import ModalDetailTransaksiBarang from './dialog/ModalDetailTransaksiBarang';
import ModalDeleteBarangJasa from './dialog/ModalDeleteBarangJasa';
import CustomNoRowsOverlay from './NoRowsOverlay';

import useGetGoods from '../../hooks/useGetGoods';
import useGetServices from '../../hooks/useGetServices';
import useGetSatuan from '../../hooks/useGetSatuan';

import { DETAIL_TRANSAKSI, KD_TRANSAKSI } from '../../constant';

const rupiahFormat = (v: any) => new Intl.NumberFormat('id-ID').format(Number(v || 0));

type Props = {
  dlkData?: any | null;
  isLoading?: boolean;
};

const DetailTransaksi: React.FC<Props> = ({ dlkData = null }) => {
  const { type } = useParams<{ type?: 'ubah' | 'pengganti' | 'new' }>();
  const apiRef = useGridApiRef();

  const isEdit = type === 'ubah';
  const isPengganti = type === 'pengganti';
  const canModify = !dlkData || isEdit || isPengganti;

  const { control, setValue } = useFormContext();

  const kdTransaksi = useWatch({ control, name: 'kdTransaksi' });
  const detailTransaksi = useWatch({ control, name: 'detailTransaksi' });
  const objekFaktur = useWatch({ control, name: 'objekFaktur' });

  const isEkspor = kdTransaksi === KD_TRANSAKSI.EXPORT;
  const isEksporBkpTidakBerwujud =
    isEkspor && detailTransaksi === DETAIL_TRANSAKSI.EKSPOR_TIDAK_BERWUJUD;
  const isEksporJasa = isEkspor && detailTransaksi === DETAIL_TRANSAKSI.EKSPOR_JASA;

  const hydratedRef = useRef(false);

  /* =========================
   * FETCH OPTIONS
   * ========================= */
  const goodsQuery = useGetGoods(isEksporBkpTidakBerwujud ? {} : undefined);
  const servicesQuery = useGetServices(isEksporJasa ? {} : undefined);
  const satuanQuery = useGetSatuan(isEksporBkpTidakBerwujud || isEksporJasa ? {} : undefined);

  const isOptionsReady = useMemo(() => {
    if (isEksporBkpTidakBerwujud) {
      return goodsQuery.isSuccess && satuanQuery.isSuccess;
    }
    if (isEksporJasa) {
      return servicesQuery.isSuccess && satuanQuery.isSuccess;
    }
    return false;
  }, [
    isEksporBkpTidakBerwujud,
    isEksporJasa,
    goodsQuery.isSuccess,
    servicesQuery.isSuccess,
    satuanQuery.isSuccess,
  ]);

  const modalPayload = useMemo(() => {
    if (isEksporBkpTidakBerwujud) {
      return { goods: goodsQuery.data ?? [], satuan: satuanQuery.data ?? [] };
    }
    if (isEksporJasa) {
      return { services: servicesQuery.data ?? [], satuan: satuanQuery.data ?? [] };
    }
    return {};
  }, [
    isEksporBkpTidakBerwujud,
    isEksporJasa,
    goodsQuery.data,
    servicesQuery.data,
    satuanQuery.data,
  ]);

  /* =========================
   * TABLE STATE (SOURCE OF TRUTH)
   * ========================= */
  const [rows, setRows] = useState<any[]>([]);
  const [editRow, setEditRow] = useState<any | null>(null);
  const [openModal, setOpenModal] = useState(false);
  const [openDelete, setOpenDelete] = useState(false);
  const [deleteId, setDeleteId] = useState<string | null>(null);

  // flags to avoid echo loop
  const isSyncingRef = useRef({ fromForm: false, fromRows: false });

  const isEqual = (a: any, b: any) => {
    try {
      return JSON.stringify(a) === JSON.stringify(b);
    } catch {
      return false;
    }
  };

  // /* =========================
  //  * FORM -> ROWS
  //  * - when parent reset(...) provides objekFaktur, hydrate grid rows
  //  * - if source is form (reset), we ALSO compute totals here once (so totals show immediately)
  //  * - set flags to avoid echo back to FORM -> ROWS
  //  * ========================= */
  useEffect(() => {
    // ===== EDIT / PENGGANTI: HYDRATE SEKALI SAJA =====
    if ((isEdit || isPengganti) && dlkData && !hydratedRef.current) {
      hydratedRef.current = true;

      const beObjek = Array.isArray(dlkData.objekFaktur) ? dlkData.objekFaktur : [];

      const normalizedFromBE = beObjek.map((it: any, idx: number) => ({
        id: it.id ?? String(idx),
        ...it,
        cekDppLain: it.cekDppLain === true,
      }));

      isSyncingRef.current.fromForm = true;
      setRows(normalizedFromBE);

      Promise.resolve().then(() => {
        isSyncingRef.current.fromForm = false;
      });

      // 👉 STOP di sini, jangan lanjut hydrate lagi
      return;
    }

    // ===== CREATE / NEW (BIARKAN SEPERTI SEKARANG) =====
    if (!Array.isArray(objekFaktur)) {
      if (rows.length > 0 && !isEqual(rows, [])) {
        isSyncingRef.current.fromForm = true;
        setRows([]);
        setTimeout(() => (isSyncingRef.current.fromForm = false), 0);
      }
      return;
    }

    const normalized = objekFaktur.map((it: any, idx: number) => ({
      id: it.id ?? String(idx),
      ...it,
      cekDppLain: it.cekDppLain === true,
    }));

    if (isSyncingRef.current.fromRows) {
      isSyncingRef.current.fromRows = false;
      return;
    }

    if (!isEqual(normalized, rows)) {
      isSyncingRef.current.fromForm = true;
      setRows(normalized);
      Promise.resolve().then(() => {
        isSyncingRef.current.fromForm = false;
      });
    }
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [objekFaktur, dlkData, isEdit, isPengganti]);

  /* =========================
   * ROWS -> FORM (when user edits grid)
   * - write objekFaktur and totals into form
   * - skip when the rows change was caused by FORM -> ROWS (to avoid loop)
   * - when edit mode, still update objekFaktur & totals if the change is user-initiated
   * ========================= */
  useEffect(() => {
    // jika perubahan rows berasal dari form reset (hydrate), abaikan sekali lalu clear flag
    if (isSyncingRef.current.fromForm) {
      isSyncingRef.current.fromForm = false;
      return;
    }

    // normalisasi rows
    const normalizedRows = rows.map((r) => ({
      ...r,
      cekDppLain: r.cekDppLain === true,
    }));

    // tandai bahwa perubahan ini berasal dari rows -> kita akan tulis ke form
    isSyncingRef.current.fromRows = true;

    // tulis objekFaktur ke form (user action)
    setValue('objekFaktur', normalizedRows, {
      shouldDirty: true,
      shouldTouch: true,
      shouldValidate: false,
    });

    // ---- HITUNG TOTALS (BERLAKU UNTUK CREATE maupun EDIT saat ini perubahan user-initiated) ----
    const sum = (k: string) => rows.reduce((a, b) => a + Number(b[k] || 0), 0);
    const sumIf = (k: string, cond: string) =>
      rows.reduce((a, b) => a + (b[cond] ? Number(b[k] || 0) : 0), 0);

    const totalJumlahBarang = sum('jmlBrgJasa');
    const totalHarga = sum('totalHarga');
    const totalDiskon = sum('diskon');
    const jumlahDpp = totalHarga;
    const totalDppLain = sumIf('dppLain', 'cekDppLain');
    const totalPpn = sum('ppn');
    const totalPpnbm = sum('ppnbm');

    setValue('totalJumlahBarang', totalJumlahBarang, { shouldDirty: false });
    setValue('totalHarga', totalHarga, { shouldDirty: false });
    setValue('totalDiskon', totalDiskon, { shouldDirty: false });

    setValue('jumlahDpp', jumlahDpp, { shouldDirty: false });
    setValue('totalDpp', jumlahDpp, { shouldDirty: false });

    setValue('jumlahDppLain', totalDppLain, { shouldDirty: false });
    setValue('totalDppLain', totalDppLain, { shouldDirty: false });

    setValue('jumlahPpn', totalPpn, { shouldDirty: false });
    setValue('totalPpn', totalPpn, { shouldDirty: false });

    setValue('jumlahPpnbm', totalPpnbm, { shouldDirty: false });
    setValue('totalPpnbm', totalPpnbm, { shouldDirty: false });

    setValue('isPpnManual', true, { shouldDirty: false });

    // clear flag fromRows di next tick (biar FORM->ROWS yg lain tidak salah paham)
    setTimeout(() => {
      isSyncingRef.current.fromRows = false;
    }, 0);
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [rows]);

  /* =========================
   * COLUMNS
   * ========================= */
  const columns = useMemo<GridColDef[]>(
    () => [
      {
        field: 'actions',
        headerName: 'Aksi',
        width: 120,
        renderCell: (params) => (
          <Stack direction="row" spacing={1}>
            <IconButton disabled={!canModify} onClick={() => handleEdit(params.row)}>
              <Edit />
            </IconButton>
            <IconButton disabled={!canModify} onClick={() => handleDelete(params.row.id)}>
              <Delete />
            </IconButton>
          </Stack>
        ),
      },
      { field: 'brgJasa', headerName: 'Tipe', width: 140 },
      { field: 'namaBrgJasa', headerName: 'Nama', width: 220 },
      { field: 'kdBrgJasa', headerName: 'Kode', width: 140 },
      { field: 'jmlBrgJasa', headerName: 'Jumlah', width: 120 },
      { field: 'satuanBrgJasa', headerName: 'Satuan', width: 120 },
      {
        field: 'hargaSatuan',
        headerName: 'Harga',
        width: 150,
        renderCell: (p) => rupiahFormat(p.value),
      },
      {
        field: 'totalHarga',
        headerName: 'Total',
        width: 150,
        renderCell: (p) => rupiahFormat(p.value),
      },
      {
        field: 'dpp',
        headerName: 'DPP',
        width: 150,
        renderCell: (p) => rupiahFormat(p.value),
      },
      {
        field: 'dppLain',
        headerName: 'DPP Lain',
        width: 150,
        renderCell: (p) => rupiahFormat(p.value),
      },
      {
        field: 'ppn',
        headerName: 'PPN',
        width: 150,
        renderCell: (p) => rupiahFormat(p.value),
      },
    ],
    [canModify]
  );

  /* =========================
   * HANDLERS
   * ========================= */
  const handleAdd = () => {
    setEditRow(null);
    setOpenModal(true);
  };

  const handleEdit = (row: any) => {
    setEditRow(row);
    setOpenModal(true);
  };

  const handleDelete = (id: string) => {
    setDeleteId(id);
    setOpenDelete(true);
  };

  const handleConfirmDelete = () => {
    const next = rows.filter((r) => r.id !== deleteId);
    setRows(next);
    setOpenDelete(false);
  };

  const handleSave = (entry: any) => {
    const normalizedEntry = {
      ...entry,
      cekDppLain: entry.cekDppLain === true,
    };

    const next = editRow
      ? rows.map((r) => (r.id === editRow.id ? { ...r, ...normalizedEntry } : r))
      : [...rows, { id: String(Date.now()), ...normalizedEntry }];

    setRows(next);
    setOpenModal(false);
    setEditRow(null);
  };

  if (!isEkspor || (!isEksporBkpTidakBerwujud && !isEksporJasa)) return null;

  console.log(rows, '123');

  return (
    <>
      <Grid size={{ xs: 12 }} sx={{ mt: 3 }}>
        <Divider sx={{ fontWeight: 'bold', fontSize: '1rem', mb: 2 }} textAlign="left">
          Detail Transaksi
        </Divider>
      </Grid>

      <Box display="flex" justifyContent="flex-end">
        <Button variant="contained" disabled={!isOptionsReady || !canModify} onClick={handleAdd}>
          Rekam
        </Button>
      </Box>

      <DataGridPremium
        columns={columns}
        apiRef={apiRef}
        rows={rows}
        initialState={{
          pinnedColumns: {
            left: ['actions'],
          },
        }}
        slots={{
          // eslint-disable-next-line react/jsx-no-useless-fragment
          toolbar: () => <></>,
          noRowsOverlay: CustomNoRowsOverlay,
        }}
        sx={{
          border: 1,
          borderColor: 'divider',
          borderRadius: 2,
          mt: 3,
          minHeight: 350,
          '& .MuiDataGrid-cell': {
            borderColor: 'divider',
            userSelect: 'text',
            cursor: 'text',
          },
          '& .MuiDataGrid-columnHeaders': { borderColor: 'divider' },
        }}
        disableVirtualization
      />

      <ModalDetailTransaksiBarang
        isOpen={openModal}
        onClose={() => setOpenModal(false)}
        payload={modalPayload}
        detailTransaksi={detailTransaksi}
        defaultValues={editRow}
        onSave={handleSave}
      />

      <ModalDeleteBarangJasa
        isOpenDialogDelete={openDelete}
        setIsOpenDialogDelete={setOpenDelete}
        dataSelected={{
          type: 'include',
          ids: new Set(deleteId ? [deleteId] : []),
        }}
        onConfirmDelete={handleConfirmDelete}
      />
    </>
  );
};

export default DetailTransaksi;
