import {
  ArticleTwoTone,
  AutorenewTwoTone,
  DeleteSweepTwoTone,
  EditNoteTwoTone,
  FileOpenTwoTone,
  HighlightOffTwoTone,
  UploadFileTwoTone,
} from '@mui/icons-material';
import Button from '@mui/material/Button';
import type {
  GridColDef,
  GridFilterModel,
  GridPaginationModel,
  GridRowSelectionModel,
  GridSortModel,
  GridToolbarProps,
} from '@mui/x-data-grid-premium';
import { DataGridPremium, useGridApiRef } from '@mui/x-data-grid-premium';
import dayjs from 'dayjs';
import { isEmpty } from 'lodash';
import { enqueueSnackbar } from 'notistack';
import { startTransition, useCallback, useEffect, useMemo, useRef, useState } from 'react';
import { unstable_batchedUpdates } from 'react-dom';
import { useNavigate } from 'react-router';
import { CustomBreadcrumbs } from 'src/components/custom-breadcrumbs';
import { DashboardContent } from 'src/layouts/dashboard';
import { RouterLink } from 'src/routes/components';
import { paths } from 'src/routes/paths';
import { FG_STATUS_BUPOT } from 'src/sections/bupot-21-26/constant';
import { appRootKey, bulanan } from 'src/sections/bupot-21-26/constant/queryKey';
import StatusChip from 'src/sections/bupot-unifikasi/bupot-dn/components/StatusChip';
import { formatRupiah } from 'src/shared/FormatRupiah/FormatRupiah';
import { useDebounce, useThrottle } from 'src/shared/hooks/useDebounceThrottle';
import { createTableKey, useTablePagination } from '../../paginationStore';
import { CustomToolbar } from '../components/dialog/CustomToolbar';
import ModalCancelBulanan from '../components/dialog/ModalCancelBulanan';
import ModalCetakPdfBulanan from '../components/dialog/ModalCetakPdfBulanan';
import ModalDeleteBulanan from '../components/dialog/ModalDeleteBulanan';
import ModalUploadBulanan from '../components/dialog/ModalUploadBulanan';
import { useAdvancedFilter } from '../hooks/useAdvancedFilter';
import useGetBulanan from '../hooks/useGetBulanan';

export type IColumnGrid = GridColDef & {
  field:
    | 'fgStatus'
    | 'noBupot'
    | 'periodeTahunan'
    | 'masaPajak'
    | 'tahunPajak'
    | 'kodeObjekPajak'
    | 'pasalPPh'
    | 'passportNo'
    | 'countryCode'
    | 'internal_id'
    | 'npwp16Dipotong'
    | 'namaDipotong'
    | 'totalPenghasilanBruto'
    | 'pph21KurangLebihBayar'
    | 'pphDipotong'
    | 'idTku'
    | 'created'
    | 'created_at'
    | 'updated'
    | 'updated_at'
    | 'internal_id'
    | 'keterangan1'
    | 'keterangan2'
    | 'keterangan3'
    | 'keterangan4'
    | 'keterangan5';
  valueOptions?: string[];
};

type Status = 'draft' | 'normal' | 'cancelled' | 'amendment';

type StatusOption = {
  value: Status;
  label: string;
};

const statusOptions: StatusOption[] = [
  { value: 'draft', label: 'Draft' },
  { value: 'normal', label: 'Normal' },
  { value: 'cancelled', label: 'Dibatalkan' },
  { value: 'amendment', label: 'Normal Pengganti' },
];

const columns: IColumnGrid[] = [
  {
    field: 'fgStatus',
    headerName: 'Status',
    headerAlign: 'center',
    align: 'left',
    width: 300,
    type: 'singleSelect',
    valueOptions: statusOptions.map((opt) => opt.value), // filter dropdown pakai value
    valueFormatter: (params: any) => {
      const option = statusOptions.find((opt) => opt.value === params.value);
      return option ? option.label : (params.value as string);
    },
    renderCell: ({ value, row }) => <StatusChip value={value} revNo={row.revNo} />,
  },
  {
    field: 'noBupot',
    headerName: 'Nomor Bukti Pemotongan',
    headerAlign: 'center',
    align: 'left',
    width: 200,
  },
  {
    field: 'internal_id',
    headerName: 'Referensi',
    minWidth: 200,
    headerAlign: 'center',
    align: 'left',
  },
  {
    field: 'masaPajak',
    headerName: 'Masa - Tahun Pajak',
    headerAlign: 'center',
    align: 'center',

    minWidth: 150,
    renderCell: (params) => `${params.row.masaPajak} - ${params.row.thnPajak}`,
  },
  {
    field: 'kodeObjekPajak',
    headerName: 'Kode Objek Pajak',
    headerAlign: 'center',
    align: 'center',
    width: 150,
    minWidth: 150,
  },
  {
    field: 'pasalPPh',
    headerName: 'Pasal PPh',
    headerAlign: 'center',
    align: 'center',
    minWidth: 150,
  },
  {
    field: 'passportNo',
    headerName: 'Nomor Paspor',
    headerAlign: 'center',
    minWidth: 200,
    align: 'left',
  },
  {
    field: 'countryCode',
    headerName: 'Negara',
    headerAlign: 'center',
    align: 'left',

    minWidth: 200,
    renderCell: (params) =>
      isEmpty(params.value) ? '' : `${params.value} - ${params.row.namaNegara}`,
  },
  {
    field: 'internal_id',
    headerName: 'Referensi',
    headerAlign: 'center',
    align: 'left',

    minWidth: 200,
  },
  {
    field: 'npwp16Dipotong',
    headerName: 'NPWP',
    headerAlign: 'center',
    align: 'left',
    minWidth: 200,
  },
  {
    field: 'namaDipotong',
    headerName: 'Nama',
    headerAlign: 'center',
    align: 'left',
    minWidth: 200,
  },
  {
    field: 'totalPenghasilanBruto',
    headerName: 'Jumlah Bruto (Rp)',
    headerAlign: 'center',
    align: 'right',
    minWidth: 200,
    valueFormatter: (params) => {
      if (params == null) {
        return '0';
      }
      return formatRupiah(params);
    },
  },
  {
    field: 'pph21KurangLebihBayar',
    headerName: 'Tunjangan PPh (Rp)',
    headerAlign: 'center',
    align: 'right',
    minWidth: 200,
    type: 'number',
    valueFormatter: (params) => {
      if (params == null) {
        return '0';
      }
      return formatRupiah(params);
    },
  },
  {
    field: 'pphDipotong',
    headerName: 'Jumlah PPh Terutang (Rp)',
    headerAlign: 'center',
    align: 'right',
    type: 'number',
    valueFormatter: (params) => {
      if (params == null) {
        return '0';
      }
      return formatRupiah(params);
    },
  },
  {
    field: 'idTku',
    headerName: 'NITKU Pemotong',
    headerAlign: 'center',
    align: 'left',
    minWidth: 200,
  },
  {
    field: 'created',
    headerName: 'Created',
    headerAlign: 'center',
    minWidth: 150,
  },
  {
    field: 'created_at',
    headerName: 'Created At',
    minWidth: 150,
    valueFormatter: (params) => dayjs(params).format('DD/MM/YYYY h:mm'),
  },
  {
    field: 'updated',
    headerName: 'Updated',
    minWidth: 150,
  },
  {
    field: 'updated_at',
    headerName: 'Update At',
    minWidth: 150,
    valueFormatter: (params) => dayjs(params).format('DD/MM/YYYY h:mm'),
  },
  {
    field: 'keterangan1',
    headerName: 'Keterangan 1',
    minWidth: 150,
  },
  {
    field: 'keterangan2',
    headerName: 'Keterangan 2',
    minWidth: 150,
  },
  {
    field: 'keterangan3',
    headerName: 'Keterangan 3',
    minWidth: 150,
  },
  {
    field: 'keterangan4',
    headerName: 'Keterangan 4',
    minWidth: 150,
  },
  {
    field: 'keterangan5',
    headerName: 'Keterangan 5',
    minWidth: 150,
  },
];

export function BulananListView() {
  const apiRef = useGridApiRef();
  const dataSelectedRef = useRef<any[]>([]);
  const navigate = useNavigate();

  const TABLE_KEY = useMemo(() => createTableKey(appRootKey, bulanan), []);
  const [paginationState, setPaginationState, resetPaginationState] = useTablePagination(TABLE_KEY);

  const { page, pageSize } = paginationState;

  // State management
  const [filterModel, setFilterModel] = useState<GridFilterModel>({ items: [] });
  const [sortModel, setSortModel] = useState<GridSortModel>([]);
  const [rowSelectionModel, setRowSelectionModel] = useState<GridRowSelectionModel | undefined>(
    undefined
  );
  // const [selectionVersion, setSelectionVersion] = useState(0);

  const [modals, setModals] = useState({
    delete: false,
    upload: false,
    cancel: false,
    preview: false,
  });
  const [previewPayload, setPreviewPayload] = useState<Record<string, any> | undefined>(undefined);

  const { buildAdvancedFilter, buildRequestParams } = useAdvancedFilter();

  const params = useMemo(() => {
    const advanced = buildAdvancedFilter(filterModel.items);
    const baseParams = {
      page: page + 1,
      limit: pageSize,
      sortingMode: sortModel[0]?.field,
      sortingMethod: sortModel[0]?.sort,
    };
    return buildRequestParams(baseParams, advanced);
  }, [page, pageSize, sortModel, filterModel.items, buildAdvancedFilter, buildRequestParams]);

  // Data fetching
  const { data, isLoading, refetch } = useGetBulanan({
    params,
    refetchOnWindowFocus: false,
  });

  const rows = useMemo(
    () => (Array.isArray(data?.data) ? data.data.filter(Boolean) : []),
    [data?.data]
  );

  const totalRows = Number(data?.total ?? 0);

  const idStatusMapRef = useRef<Map<string | number, string>>(new Map());

  useEffect(() => {
    if (!rows.length) {
      idStatusMapRef.current.clear();
      return;
    }

    const newMap = new Map<string | number, string>();
    rows.forEach((r: any) => {
      const id = String(r.id ?? r.internal_id ?? '');
      if (id) newMap.set(id, r?.fgStatus ?? '');
    });

    idStatusMapRef.current = newMap;
  }, [rows]);

  const handlePaginationChange = useCallback(
    (model: GridPaginationModel) => {
      if (model.pageSize !== pageSize) {
        // Reset to first page when page size changes
        setPaginationState({ page: 0, pageSize: model.pageSize });
      } else {
        setPaginationState({ page: model.page });
      }
    },
    [pageSize, setPaginationState]
  );

  const handleFilterChange = useCallback(
    (model: GridFilterModel) => {
      setFilterModel(model);
      resetPaginationState(); // Reset ke page 0 saat filter berubah
    },
    [resetPaginationState]
  );

  const handleSortChange = useCallback(
    (model: GridSortModel) => {
      setSortModel(model);
      resetPaginationState(); // Reset ke page 0 saat sort berubah
    },
    [resetPaginationState]
  );

  const throttledPaginationChange = useThrottle(handlePaginationChange, 250);
  const debouncedFilterChange = useDebounce(handleFilterChange, 400);
  const debouncedSortChange = useDebounce(handleSortChange, 400);

  const toggleModal = useCallback((modalName: keyof typeof modals, value: boolean) => {
    setModals((prev) => ({ ...prev, [modalName]: value }));
  }, []);

  const handleEditData = useCallback(
    (type = 'ubah') => {
      const selectedRow = dataSelectedRef.current[0];
      if (!selectedRow) {
        enqueueSnackbar('Pilih data yang akan diubah', { variant: 'warning' });
        return;
      }
      navigate(`/pph21/bulanan/${selectedRow.id}/${type}`);
    },
    [navigate]
  );

  const handleOpenPreview = useCallback(() => {
    const selectedRow = dataSelectedRef.current?.[0];
    if (!selectedRow) {
      enqueueSnackbar('Pilih 1 baris untuk melihat detail', { variant: 'warning' });
      return;
    }
    setPreviewPayload(selectedRow);
    toggleModal('preview', true);
  }, [toggleModal]);

  const throttledSelectionChange = useThrottle((newSelection: any) => {
    if (!apiRef.current) return;

    const ids =
      newSelection?.ids instanceof Set ? Array.from(newSelection.ids) : newSelection || [];

    const selectedData = ids.map((id: any) => apiRef.current!.getRow(id)).filter(Boolean);

    // Batch updates
    unstable_batchedUpdates(() => {
      dataSelectedRef.current = selectedData;
      setRowSelectionModel(newSelection);
      // setSelectionVersion((v) => v + 1);
    });
  }, 150);

  useEffect(() => {
    const api = apiRef.current;
    if (!api) return;

    const handleRowsSet = () => {
      const exec = () => {
        const ids =
          api.state?.rowSelection?.ids instanceof Set ? Array.from(api.state.rowSelection.ids) : [];

        const updatedSelected = ids.map((id) => api.getRow(id)).filter(Boolean);

        dataSelectedRef.current = updatedSelected;
        // setSelectionVersion((v) => v + 1);
      };

      if ((window as any).requestIdleCallback) {
        (window as any).requestIdleCallback(exec);
      } else {
        setTimeout(exec, 0);
      }
    };

    const unsubscribe = api.subscribeEvent('rowsSet', handleRowsSet);
    // eslint-disable-next-line consistent-return
    return () => unsubscribe();
  }, [apiRef]);

  const validatedActions = useMemo(() => {
    const dataSelected = dataSelectedRef.current;
    const count = dataSelected.length;
    const hasSelection = count > 0;

    if (!hasSelection) {
      return {
        canDetail: false,
        canEdit: false,
        canDelete: false,
        canUpload: false,
        canReplacement: false,
        canCancel: false,
      };
    }

    const allDraft = dataSelected.every((d) => d.fgStatus === FG_STATUS_BUPOT.DRAFT);
    const allNormal = dataSelected.every((d) => d.fgStatus === FG_STATUS_BUPOT.NORMAL_DONE);
    const firstItem = dataSelected[0];

    return {
      canDetail: count === 1,
      canEdit: count === 1 && allDraft,
      canDelete: hasSelection && allDraft,
      canUpload: hasSelection && allDraft,
      canReplacement: count === 1 && firstItem?.fgStatus === FG_STATUS_BUPOT.NORMAL_DONE,
      canCancel: hasSelection && allNormal,
    };
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [dataSelectedRef.current]);

  const actions = useMemo(
    () => [
      [
        {
          title: 'Refresh List',
          icon: <AutorenewTwoTone sx={{ width: 26, height: 26 }} />,
          func: () => startTransition(() => void refetch()),
        },
        {
          title: 'Edit',
          icon: <EditNoteTwoTone sx={{ width: 26, height: 26 }} />,
          func: () => handleEditData('ubah'),
          disabled: !validatedActions.canEdit,
        },
        {
          title: 'Detail',
          icon: <ArticleTwoTone sx={{ width: 26, height: 26 }} />,
          func: handleOpenPreview,
          disabled: !validatedActions.canDetail,
        },
        {
          title: 'Hapus',
          icon: <DeleteSweepTwoTone sx={{ width: 26, height: 26 }} />,
          func: () => toggleModal('delete', true),
          disabled: !validatedActions.canDelete,
        },
      ],
      [
        {
          title: 'Upload',
          icon: <UploadFileTwoTone sx={{ width: 26, height: 26 }} />,
          func: () => toggleModal('upload', true),
          disabled: !validatedActions.canUpload,
        },
        {
          title: 'Pengganti',
          icon: <FileOpenTwoTone sx={{ width: 26, height: 26 }} />,
          func: () => handleEditData('pengganti'),
          disabled: !validatedActions.canReplacement,
        },
        {
          title: 'Batal',
          icon: <HighlightOffTwoTone sx={{ width: 26, height: 26 }} />,
          func: () => toggleModal('cancel', true),
          disabled: !validatedActions.canCancel,
        },
      ],
    ],
    [validatedActions, refetch, handleEditData, handleOpenPreview, toggleModal]
  );

  const pinnedColumns = useMemo(() => ({ left: ['__check__', 'fgStatus', 'noBupot'] }), []);

  const ToolbarWrapper: React.FC<GridToolbarProps> = useCallback(
    (gridToolbarProps) => (
      <CustomToolbar
        actions={actions}
        columns={columns}
        filterModel={filterModel}
        setFilterModel={setFilterModel}
        statusOptions={statusOptions}
        {...gridToolbarProps}
      />
    ),
    [actions, filterModel]
  );

  const paginationModel: GridPaginationModel = useMemo(
    () => ({ page, pageSize }),
    [page, pageSize]
  );

  return (
    <DashboardContent>
      <CustomBreadcrumbs
        heading="Bupot Bulanan"
        links={[
          { name: 'Dashboard', href: paths.dashboard.root },
          { name: 'e-Bupot PPh Pasal 21 Bulanan' },
        ]}
        action={
          <Button component={RouterLink} href={paths.pph21.bulananRekam} variant="contained" sx={{backgroundColor: "var(--palette-primary-main)"}}>
            Rekam Data
          </Button>
        }
      />

      <DataGridPremium
        apiRef={apiRef}
        checkboxSelection
        rows={rows}
        columns={columns}
        loading={isLoading}
        rowCount={totalRows}
        disableVirtualization
        pagination
        paginationMode="server"
        paginationModel={paginationModel}
        onPaginationModelChange={throttledPaginationChange}
        pageSizeOptions={[5, 10, 15, 25, 50, 100]}
        filterMode="server"
        onFilterModelChange={debouncedFilterChange}
        sortingMode="server"
        onSortModelChange={debouncedSortChange}
        rowSelectionModel={rowSelectionModel}
        onRowSelectionModelChange={throttledSelectionChange}
        pinnedColumns={pinnedColumns}
        cellSelection
        slots={{ toolbar: ToolbarWrapper }}
        sx={{
          border: 1,
          borderColor: 'divider',
          borderRadius: 2,
          mt: 3,
          '& .MuiDataGrid-cell': {
            borderColor: 'divider',
            userSelect: 'text',
            cursor: 'text',
          },
          '& .MuiDataGrid-columnHeaders': { borderColor: 'divider' },
        }}
      />

      {modals.delete && (
        <ModalDeleteBulanan
          dataSelected={rowSelectionModel}
          setSelectionModel={setRowSelectionModel}
          tableApiRef={apiRef}
          isOpenDialogDelete={modals.delete}
          setIsOpenDialogDelete={() => toggleModal('delete', false)}
          successMessage="Data berhasil dihapus"
        />
      )}
      {modals.upload && (
        <ModalUploadBulanan
          dataSelected={rowSelectionModel}
          setSelectionModel={setRowSelectionModel}
          tableApiRef={apiRef}
          isOpenDialogUpload={modals.upload}
          setIsOpenDialogUpload={() => toggleModal('upload', false)}
          successMessage="Data berhasil diupload"
        />
      )}
      {modals.cancel && (
        <ModalCancelBulanan
          dataSelected={dataSelectedRef.current}
          setSelectionModel={setRowSelectionModel}
          tableApiRef={apiRef}
          isOpenDialogCancel={modals.cancel}
          setIsOpenDialogCancel={() => toggleModal('cancel', false)}
          successMessage="Data berhasil Canceled"
        />
      )}
      {modals.preview && previewPayload && (
        <ModalCetakPdfBulanan
          payload={previewPayload}
          isOpen={modals.preview}
          onClose={() => {
            toggleModal('preview', false);
            setPreviewPayload(undefined);
          }}
        />
      )}
    </DashboardContent>
  );
}
