'use client';

import { ChangeEventHandler, useEffect, useMemo, useState } from 'react';
import useSWR from 'swr';
import {
  CellContext,
  ColumnDef,
  Row,
  SortingState,
} from '@tanstack/react-table';
import toast from 'react-hot-toast';

import { Icon } from '@iconify/react';
import Table from '@/components/Table';
import DebouncedTextInput from '@/components/input/DebouncedTextInput';
import Button from '@/components/Button';
import { useModal } from '@/components/Modal';
import ConfirmationModal from '@/components/modal/ConfirmationModal';
import SelectInput, {
  OptionType,
  useSelect,
} from '@/components/input/SelectInput';
import RowDropdownOptions from '@/components/table/RowDropdownOptions';
import RowCollapseOptions from '@/components/table/RowCollapseOptions';
import RowOptionsMenuWrapper from '@/components/table/RowOptionsMenuWrapper';
import RealizationStatusBadge from '@/components/pages/expense/RealizationStatusBadge';
import ExpenseStatusBadge from '@/components/pages/expense/ExpenseStatusBadge';
import CheckboxInput from '@/components/input/CheckboxInput';
import ConfirmationModalWithNotes from '@/components/modal/ConfirmationModalWithNotes';
import DateInput from '@/components/input/DateInput';
import RequirePermission from '@/components/helper/RequirePermission';

import { Expense } from '@/types/api/expense';
import { ExpenseApi } from '@/services/api/expense';
import { cn, formatCurrency, formatDate } from '@/lib/helper';
import { isResponseSuccess } from '@/lib/api-helper';
import { useTableFilter } from '@/services/hooks/useTableFilter';
import { LocationApi, SupplierApi } from '@/services/api/master-data';
import { Location } from '@/types/api/master-data/location';
import { Supplier } from '@/types/api/master-data/supplier';
import { BaseApiResponse } from '@/types/api/api-general';

const RowOptionsMenu = ({
  type = 'dropdown',
  props,
  deleteClickHandler,
}: {
  type: 'dropdown' | 'collapse';
  props: CellContext<Expense, unknown>;
  approveClickHandler: () => void;
  rejectClickHandler: () => void;
  deleteClickHandler: () => void;
}) => {
  const showEditButton = props.row.original.latest_approval
    ? props.row.original.latest_approval.step_number !== 6 &&
      (props.row.original.latest_approval.step_number === 1 ||
        props.row.original.latest_approval.step_number === 2 ||
        props.row.original.latest_approval.step_number === 3 ||
        props.row.original.latest_approval.step_number === 4)
    : false;

  // TODO: apply RBAC
  const showRealizationButton = props.row.original.latest_approval
    ? props.row.original.latest_approval.action !== 'REJECTED' &&
      props.row.original.latest_approval.step_number === 4
    : false;

  return (
    <RowOptionsMenuWrapper type={type}>
      <div className='w-full max-h-40 overflow-auto flex flex-col gap-1'>
        <RequirePermission permissions='lti.expense.detail'>
          <Button
            href={`/expense/detail/?expenseId=${props.row.original.id}`}
            variant='ghost'
            color='primary'
            className='justify-start text-sm'
          >
            <Icon icon='mdi:eye-outline' width={16} height={16} />
            Detail
          </Button>
        </RequirePermission>

        {showEditButton && (
          <RequirePermission permissions='lti.expense.update'>
            <Button
              href={`/expense/detail/edit/?expenseId=${props.row.original.id}`}
              variant='ghost'
              color='warning'
              className='justify-start text-sm'
            >
              <Icon
                icon='material-symbols:edit-outline'
                width={16}
                height={16}
              />
              Edit
            </Button>
          </RequirePermission>
        )}

        {showRealizationButton && (
          <RequirePermission permissions='lti.expense.create.realization'>
            <Button
              href={`/expense/realization/?expenseId=${props.row.original.id}`}
              variant='ghost'
              color='info'
              className='justify-start text-sm text-info focus-visible:text-info-content hover:text-info-content'
            >
              <Icon
                icon='material-symbols:money-bag-rounded'
                width={16}
                height={16}
              />
              Realisasi
            </Button>
          </RequirePermission>
        )}

        <RequirePermission permissions='lti.expense.delete'>
          <Button
            onClick={deleteClickHandler}
            variant='ghost'
            color='error'
            className='justify-start text-sm text-error focus-visible:text-error-content hover:text-error-content'
          >
            <Icon
              icon='material-symbols:delete-outline-rounded'
              width={16}
              height={16}
              className='justify-start text-sm'
            />
            Delete
          </Button>
        </RequirePermission>
      </div>
    </RowOptionsMenuWrapper>
  );
};

const ExpensesTable = () => {
  const {
    state: tableFilterState,
    updateFilter,
    setPage,
    setPageSize,
    toQueryString: getTableFilterQueryString,
  } = useTableFilter({
    initial: {
      search: '',
      nameSort: '',
      transactionDate: '',
      realizationDate: '',
      locationId: '',
      vendorId: '',
      userId: '',
    },
    paramMap: {
      page: 'page',
      pageSize: 'limit',
      nameSort: 'sort_name',
      transactionDate: 'transaction_date',
      realizationDate: 'realization_date',
      locationId: 'location_id',
      vendorId: 'vendor_id',
      userId: 'user_id',
    },
  });

  const {
    data: expenses,
    isLoading,
    mutate: refreshExpenses,
  } = useSWR(
    `${ExpenseApi.basePath}${getTableFilterQueryString()}`,
    ExpenseApi.getAllFetcher
  );

  const deleteModal = useModal();
  const approveModal = useModal();
  const rejectModal = useModal();

  const [selectedExpense, setSelectedExpense] = useState<Expense | undefined>(
    undefined
  );
  const [isDeleteLoading, setIsDeleteLoading] = useState(false);
  const [isApproveLoading, setIsApproveLoading] = useState(false);
  const [isRejectLoading, setIsRejectLoading] = useState(false);
  const [, setApprovalNotes] = useState('');

  const [sorting, setSorting] = useState<SortingState>([]);
  const [rowSelection, setRowSelection] = useState<Record<string, boolean>>({});
  const selectedRowIds = Object.keys(rowSelection).map((item) =>
    parseInt(item)
  );

  const isAllSelectedRowLatestApprovalOnHeadArea = useMemo(() => {
    return selectedRowIds.every((rowId) => {
      if (!isResponseSuccess(expenses)) return false;

      const expenseItem = expenses.data.find((item) => item.id === rowId);

      const isLatestApprovalRejected =
        expenseItem?.latest_approval.action === 'REJECTED';

      const isCurrentApprovalOnHeadArea =
        !isLatestApprovalRejected &&
        expenseItem?.latest_approval.step_number === 1;

      return isCurrentApprovalOnHeadArea;
    });
  }, [expenses, selectedRowIds]);

  const isAllSelectedRowLatestApprovalOnUnitVicePresident = useMemo(() => {
    return selectedRowIds.every((rowId) => {
      if (!isResponseSuccess(expenses)) return false;

      const expenseItem = expenses.data.find((item) => item.id === rowId);

      const isLatestApprovalRejected =
        expenseItem?.latest_approval.action === 'REJECTED';

      const isCurrentApprovalOnUnitVicePresident =
        !isLatestApprovalRejected &&
        expenseItem?.latest_approval.step_number === 2;

      return isCurrentApprovalOnUnitVicePresident;
    });
  }, [expenses, selectedRowIds]);

  const isAllSelectedRowLatestApprovalOnFinance = useMemo(() => {
    return selectedRowIds.every((rowId) => {
      if (!isResponseSuccess(expenses)) return false;

      const expenseItem = expenses.data.find((item) => item.id === rowId);

      const isLatestApprovalRejected =
        expenseItem?.latest_approval.action === 'REJECTED';

      const isCurrentApprovalOnFinance =
        !isLatestApprovalRejected &&
        expenseItem?.latest_approval.step_number === 3;

      return isCurrentApprovalOnFinance;
    });
  }, [expenses, selectedRowIds]);

  const expensesColumns: ColumnDef<Expense>[] = [
    {
      id: 'select',
      header: ({ table }) => (
        <div className='w-full flex flex-row justify-center'>
          <CheckboxInput
            name='allRow'
            checked={table.getIsAllRowsSelected()}
            indeterminate={table.getIsSomeRowsSelected()}
            onChange={table.getToggleAllRowsSelectedHandler()}
          />
        </div>
      ),
      cell: ({ row }) => {
        const isCheckboxDisabled =
          !row.getCanSelect() ||
          !row.original.latest_approval ||
          row.original.latest_approval.action === 'REJECTED';

        return (
          <div>
            <CheckboxInput
              name='row'
              checked={row.getIsSelected()}
              disabled={isCheckboxDisabled}
              indeterminate={row.getIsSomeSelected()}
              onChange={row.getToggleSelectedHandler()}
            />
          </div>
        );
      },
    },
    {
      accessorKey: 'reference_number',
      header: 'Nomor Referensi',
      cell: (props) => {
        return props.row.original.reference_number ?? '-';
      },
    },
    {
      accessorKey: 'transaction_date',
      header: 'Tanggal Pengajuan',
      cell: (props) =>
        props.row.original.transaction_date
          ? formatDate(props.row.original.transaction_date, 'DD MMM YYYY')
          : '-',
    },
    {
      accessorKey: 'realization_date',
      header: 'Tanggal Realisasi',
      cell: (props) =>
        props.row.original.realization_date
          ? formatDate(props.row.original.realization_date, 'DD MMM YYYY')
          : '-',
    },
    {
      accessorKey: 'location',
      header: 'Lokasi',
      cell: (props) => props.row.original.location?.name ?? '-',
    },
    {
      accessorFn: (row) => row.created_user.name ?? '-',
      header: 'Nama Pengaju',
    },
    {
      accessorFn: (row) => row.supplier.name ?? '-',
      header: 'Vendor',
    },
    {
      accessorKey: 'grand_total',
      header: 'Nominal',
      cell: (props) =>
        props.row.original.grand_total
          ? formatCurrency(props.row.original.grand_total)
          : '-',
    },
    {
      header: 'Status Pencairan',
      cell: (props) => (
        <RealizationStatusBadge approval={props.row.original.latest_approval} />
      ),
    },
    {
      header: 'Status BOP',
      cell: (props) => (
        <ExpenseStatusBadge approval={props.row.original.latest_approval} />
      ),
    },
    {
      header: 'Aksi',
      cell: (props) => {
        const currentPageSize = props.table.getPaginationRowModel().rows.length;
        const currentPageRows = props.table.getPaginationRowModel().flatRows;
        const currentRowRelativeIndex =
          currentPageRows.findIndex((r) => r.id === props.row.id) + 1;

        const isLast2Rows = currentRowRelativeIndex > currentPageSize - 3;

        const approveClickHandler = () => {
          setSelectedExpense(props.row.original);

          // Set row selection
          setRowSelection({
            [String(props.row.original.id)]: true,
          });

          setApprovalNotes('');
          approveModal.openModal();
        };

        const rejectClickHandler = () => {
          setSelectedExpense(props.row.original);

          // Set row selection
          setRowSelection({
            [String(props.row.original.id)]: true,
          });

          setApprovalNotes('');
          rejectModal.openModal();
        };

        const deleteClickHandler = () => {
          setSelectedExpense(props.row.original);
          deleteModal.openModal();
        };

        return (
          <>
            {currentPageSize > 3 && (
              <RowDropdownOptions isLast2Rows={isLast2Rows}>
                <RowOptionsMenu
                  type='dropdown'
                  props={props}
                  approveClickHandler={approveClickHandler}
                  rejectClickHandler={rejectClickHandler}
                  deleteClickHandler={deleteClickHandler}
                />
              </RowDropdownOptions>
            )}

            {currentPageSize <= 3 && (
              <RowCollapseOptions>
                <RowOptionsMenu
                  type='collapse'
                  props={props}
                  approveClickHandler={approveClickHandler}
                  rejectClickHandler={rejectClickHandler}
                  deleteClickHandler={deleteClickHandler}
                />
              </RowCollapseOptions>
            )}
          </>
        );
      },
    },
  ];

  const tableEnableRowSelectionHandler: (row: Row<Expense>) => boolean = (
    row
  ) => {
    if (!row.original.latest_approval) return false;

    return (
      row.original.latest_approval.action !== 'REJECTED' &&
      row.original.latest_approval.step_number !== 6
    );
  };

  // const bulkApproveClickHandler = () => {
  //   approveModal.openModal();
  // };

  // const bulkRejectClickHandler = () => {
  //   rejectModal.openModal();
  // };

  const bulkApproveClickHandler = () => {
    setApprovalNotes('');
    approveModal.openModal();
  };

  const bulkRejectClickHandler = () => {
    setApprovalNotes('');
    rejectModal.openModal();
  };

  const confirmationModalDeleteClickHandler = async () => {
    setIsDeleteLoading(true);

    const deleteResponse = await ExpenseApi.delete(
      selectedExpense?.id as number
    );

    if (isResponseSuccess(deleteResponse)) {
      refreshExpenses();
      deleteModal.closeModal();
      toast.success('Berhasil menghapus biaya operasional!');
    } else {
      deleteModal.closeModal();
      toast.error('Gagal menghapus biaya operasional!');
    }

    setIsDeleteLoading(false);
  };

  const confirmationModalApproveClickHandler = async (notes: string) => {
    setIsApproveLoading(true);

    let bulkApproveResponse: BaseApiResponse<Expense> | undefined = undefined;

    if (isAllSelectedRowLatestApprovalOnHeadArea) {
      bulkApproveResponse = await ExpenseApi.bulkApproveHeadArea(
        selectedRowIds,
        notes
      );
    } else if (isAllSelectedRowLatestApprovalOnUnitVicePresident) {
      bulkApproveResponse = await ExpenseApi.bulkApproveUnitVicePresident(
        selectedRowIds,
        notes
      );
    } else if (isAllSelectedRowLatestApprovalOnFinance) {
      bulkApproveResponse = await ExpenseApi.bulkApproveFinance(
        selectedRowIds,
        notes
      );
    }

    if (isResponseSuccess(bulkApproveResponse)) {
      refreshExpenses();
      approveModal.closeModal();

      toast.success(
        `Berhasil approve ${selectedRowIds.length} data biaya operasional!`
      );

      setApprovalNotes('');
      setRowSelection({});
    } else {
      approveModal.closeModal();

      toast.error(
        `Gagal approve ${selectedRowIds.length} data biaya operasional!`
      );
    }

    setIsApproveLoading(false);
  };

  const confirmationModalRejectClickHandler = async (notes: string) => {
    setIsRejectLoading(true);

    let bulkRejectResponse: BaseApiResponse<Expense> | undefined = undefined;

    if (isAllSelectedRowLatestApprovalOnHeadArea) {
      bulkRejectResponse = await ExpenseApi.bulkRejectHeadArea(
        selectedRowIds,
        notes
      );
    } else if (isAllSelectedRowLatestApprovalOnUnitVicePresident) {
      bulkRejectResponse = await ExpenseApi.bulkRejectUnitVicePresident(
        selectedRowIds,
        notes
      );
    } else if (isAllSelectedRowLatestApprovalOnFinance) {
      bulkRejectResponse = await ExpenseApi.bulkRejectFinance(
        selectedRowIds,
        notes
      );
    }

    if (isResponseSuccess(bulkRejectResponse)) {
      refreshExpenses();
      rejectModal.closeModal();

      toast.success(
        `Berhasil reject ${selectedRowIds.length} data biaya operasional!`
      );
      setApprovalNotes('');
      setRowSelection({});
    } else {
      rejectModal.closeModal();

      toast.error(
        `Gagal reject ${selectedRowIds.length} data biaya operasional!`
      );
    }

    setIsRejectLoading(false);
  };

  const {
    setInputValue: setLocationInputValue,
    options: locationOptions,
    isLoadingOptions: isLoadingLocationOptions,
  } = useSelect<Location>(LocationApi.basePath, 'id', 'name');

  const [selectedLocation, setSelectedLocation] = useState<OptionType | null>(
    null
  );

  const locationChangeHandler = (val: OptionType | OptionType[] | null) => {
    setSelectedLocation(val as OptionType);
    updateFilter(
      'locationId',
      val ? ((val as OptionType).value as string) : ''
    );
  };

  const {
    setInputValue: setVendorInputValue,
    options: vendorOptions,
    isLoadingOptions: isLoadingVendorOptions,
  } = useSelect<Supplier>(SupplierApi.basePath, 'id', 'name');

  const [selectedVendor, setSelectedVendor] = useState<OptionType | null>(null);

  const vendorChangeHandler = (val: OptionType | OptionType[] | null) => {
    setSelectedVendor(val as OptionType);
    updateFilter('vendorId', val ? ((val as OptionType).value as string) : '');
  };

  const searchChangeHandler: ChangeEventHandler<HTMLInputElement> = (e) => {
    updateFilter('search', e.target.value);
  };

  const transactionDateChangeHandler: ChangeEventHandler<HTMLInputElement> = (
    e
  ) => {
    updateFilter('transactionDate', e.target.value);
  };

  const realizationDateChangeHandler: ChangeEventHandler<HTMLInputElement> = (
    e
  ) => {
    updateFilter('realizationDate', e.target.value);
  };

  // track sorting
  useEffect(() => {
    const isNameSorted = sorting.find((sortItem) => sortItem.id === 'name');

    if (!isNameSorted) {
      updateFilter('nameSort', '');
    } else {
      updateFilter('nameSort', isNameSorted.desc ? 'desc' : 'asc');
    }
  }, [sorting, updateFilter]);

  return (
    <>
      <div className='w-full p-0 sm:p-4'>
        <div className='flex flex-col gap-2 mb-4'>
          <div className='flex flex-col gap-2 mb-4'>
            <div className='w-full flex flex-col sm:flex-row justify-between items-end sm:items-center gap-4'>
              <div className='w-full sm:w-fit flex flex-col sm:flex-row self-start gap-2'>
                <RequirePermission permissions='lti.expense.create'>
                  <Button
                    href='/expense/add'
                    color='primary'
                    className='px-3 py-2.5 w-fit text-sm text-base-100 rounded-lg shadow-sm'
                  >
                    <Icon icon='heroicons:plus' width={20} height={20} />
                    Add Expense
                  </Button>
                </RequirePermission>

                {selectedRowIds.length > 0 && (
                  <>
                    <RequirePermission permissions='lti.expense.approve.head_area'>
                      <Button
                        variant='outline'
                        color='info'
                        onClick={bulkApproveClickHandler}
                        disabled={!isAllSelectedRowLatestApprovalOnHeadArea}
                        className='w-full sm:w-fit'
                      >
                        <Icon icon='lucide-lab:farm' width={24} height={24} />
                        Approve Head Area
                      </Button>
                    </RequirePermission>

                    <RequirePermission permissions='lti.expense.approve.unit_vice_president'>
                      <Button
                        variant='outline'
                        color='success'
                        onClick={bulkApproveClickHandler}
                        disabled={
                          !isAllSelectedRowLatestApprovalOnUnitVicePresident
                        }
                        className='w-full sm:w-fit'
                      >
                        <Icon icon='tdesign:money' width={24} height={24} />
                        Approve Unit Vice President
                      </Button>
                    </RequirePermission>

                    <RequirePermission permissions='lti.expense.approve.finance'>
                      <Button
                        variant='outline'
                        color='success'
                        onClick={bulkApproveClickHandler}
                        disabled={!isAllSelectedRowLatestApprovalOnFinance}
                        className='w-full sm:w-fit'
                      >
                        <Icon icon='tdesign:money' width={24} height={24} />
                        Approve Finance
                      </Button>
                    </RequirePermission>

                    <RequirePermission
                      permissions={[
                        'lti.expense.approve.head_area',
                        'lti.expense.approve.unit_vice_president',
                        'lti.expense.approve.finance',
                      ]}
                    >
                      <Button
                        variant='outline'
                        color='error'
                        onClick={bulkRejectClickHandler}
                        disabled={
                          !isAllSelectedRowLatestApprovalOnHeadArea &&
                          !isAllSelectedRowLatestApprovalOnUnitVicePresident &&
                          !isAllSelectedRowLatestApprovalOnFinance
                        }
                        className='w-full sm:w-fit'
                      >
                        <Icon
                          icon='material-symbols:close'
                          width={24}
                          height={24}
                        />
                        Reject
                      </Button>
                    </RequirePermission>
                  </>
                )}
              </div>
            </div>

            <div className='grid grid-cols-12 justify-end gap-2'>
              <DateInput
                required
                label='Tanggal Transaksi'
                name='transaction_date'
                placeholder='Masukkan tanggal transaksi'
                value={tableFilterState.transactionDate}
                onChange={transactionDateChangeHandler}
                className={{
                  wrapper: 'col-span-12 sm:col-span-3',
                }}
              />

              <DateInput
                required
                label='Tanggal Realisasi'
                name='realization_date'
                placeholder='Masukkan tanggal realisasi'
                value={tableFilterState.realizationDate}
                onChange={realizationDateChangeHandler}
                className={{
                  wrapper: 'col-span-12 sm:col-span-3',
                }}
              />

              <SelectInput
                label='Lokasi'
                options={locationOptions}
                isLoading={isLoadingLocationOptions}
                value={selectedLocation}
                onChange={locationChangeHandler}
                onInputChange={setLocationInputValue}
                isClearable
                className={{
                  wrapper: 'col-span-12 sm:col-span-3',
                }}
              />

              <SelectInput
                label='Vendor'
                options={vendorOptions}
                isLoading={isLoadingVendorOptions}
                value={selectedVendor}
                onChange={vendorChangeHandler}
                onInputChange={setVendorInputValue}
                isClearable
                className={{
                  wrapper: 'col-span-12 sm:col-span-3',
                }}
              />

              <DebouncedTextInput
                name='search'
                placeholder='Cari Biaya Operasional'
                value={tableFilterState.search}
                onChange={searchChangeHandler}
                className={{ wrapper: 'col-span-12 max-w-52 justify-self-end' }}
              />
            </div>
          </div>
        </div>

        <Table<Expense>
          data={isResponseSuccess(expenses) ? expenses?.data : []}
          columns={expensesColumns}
          pageSize={tableFilterState.pageSize}
          page={isResponseSuccess(expenses) ? expenses?.meta?.page : 0}
          totalItems={
            isResponseSuccess(expenses) ? expenses?.meta?.total_results : 0
          }
          onPageChange={setPage}
          isLoading={isLoading}
          sorting={sorting}
          setSorting={setSorting}
          rowSelection={rowSelection}
          setRowSelection={setRowSelection}
          enableRowSelection={tableEnableRowSelectionHandler}
          className={{
            containerClassName: cn({
              'mb-20':
                isResponseSuccess(expenses) && expenses?.data?.length === 0,
            }),
            tableWrapperClassName: 'overflow-x-auto min-h-full!',
            tableClassName: 'font-inter w-full table-auto min-h-full!',
            headerRowClassName: 'border-b border-b-gray-200',
            headerColumnClassName:
              'px-6 py-3 text-xs font-semibold text-gray-500 last:flex last:flex-row last:justify-end',
            bodyRowClassName: 'border-b border-b-gray-200',
            bodyColumnClassName:
              'px-6 py-3 last:flex last:flex-row last:justify-end',
          }}
        />
      </div>

      <ConfirmationModal
        ref={deleteModal.ref}
        type='error'
        text='Apakah anda yakin ingin menghapus data biaya operasional ini?'
        secondaryButton={{
          text: 'Tidak',
        }}
        primaryButton={{
          text: 'Ya',
          color: 'error',
          isLoading: isDeleteLoading,
          onClick: confirmationModalDeleteClickHandler,
        }}
      />

      <ConfirmationModalWithNotes
        ref={approveModal.ref}
        type='success'
        text='Apakah anda yakin ingin approve data biaya operasional ini?'
        secondaryButton={{
          text: 'Tidak',
          onClick: () => {
            setApprovalNotes('');
            approveModal.closeModal();
          },
        }}
        primaryButton={{
          text: 'Ya',
          color: 'success',
          isLoading: isApproveLoading,
          onClick: confirmationModalApproveClickHandler,
        }}
      />

      <ConfirmationModalWithNotes
        ref={rejectModal.ref}
        type='error'
        text='Apakah anda yakin ingin reject data biaya operasional ini?'
        secondaryButton={{
          text: 'Tidak',
          onClick: () => {
            setApprovalNotes('');
            rejectModal.closeModal();
          },
        }}
        primaryButton={{
          text: 'Ya',
          color: 'error',
          isLoading: isRejectLoading,
          onClick: confirmationModalRejectClickHandler,
        }}
      />
    </>
  );
};

export default ExpensesTable;
