import { ChangeEventHandler, useMemo, useState } from 'react';
import { CellContext } from '@tanstack/react-table';
import { useSearchParams } from 'next/navigation';
import useSWR from 'swr';

import Button from '@/components/Button';
import Card from '@/components/Card';
import DateInput from '@/components/input/DateInput';
import DebouncedTextInput from '@/components/input/DebouncedTextInput';
import SelectInput, {
  OptionType,
  useSelect,
} from '@/components/input/SelectInput';
import Table from '@/components/Table';
import { formatCurrency, formatDate, formatTitleCase } from '@/lib/helper';
import { useTableFilter } from '@/services/hooks/useTableFilter';
import { Finance } from '@/types/api/finance/finance';
import {
  FINANCE_INITIAL_BALANCE_STATUS,
  FINANCE_INJECTION_STATUS,
  FINANCE_TRANSACTION_STATUS,
} from '@/config/constant';
import { FinanceApi } from '@/services/api/finance';
import { isResponseSuccess } from '@/lib/api-helper';
import { BankApi } from '@/services/api/master-data';
import { Bank } from '@/types/api/master-data/bank';
import { useModal } from '@/components/Modal';
import ConfirmationModal from '@/components/modal/ConfirmationModal';
import toast from 'react-hot-toast';
import RowOptionsMenuWrapper from '@/components/table/RowOptionsMenuWrapper';
import RequirePermission from '@/components/helper/RequirePermission';
import { Icon } from '@iconify/react';
import RowDropdownOptions from '@/components/table/RowDropdownOptions';
import RowCollapseOptions from '@/components/table/RowCollapseOptions';

const RowOptionsMenu = ({
  type = 'dropdown',
  props,
  deleteClickHandler,
}: {
  type: 'dropdown' | 'collapse';
  props: CellContext<Finance, unknown>;
  deleteClickHandler: () => void;
}) => {
  return (
    <RowOptionsMenuWrapper type={type}>
      <RequirePermission
        permissions={[
          'lti.finance.transactions.detail',
          'lti.finance.initial_balances.detail',
          'lti.finance.injections.detail',
          'lti.finance.payments.detail',
        ]}
      >
        <Button
          href={`/finance/detail?financeId=${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>

      {FINANCE_TRANSACTION_STATUS.includes(
        props.row.original.transaction_type
      ) && (
        <RequirePermission permissions='lti.finance.payments.update'>
          <Button
            href={`/finance/detail/edit?financeId=${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>
      )}

      {FINANCE_INITIAL_BALANCE_STATUS.includes(
        props.row.original.transaction_type
      ) && (
        <RequirePermission permissions='lti.finance.initial_balances.update'>
          <Button
            href={`/finance/detail/edit/initial-balance?financeId=${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>
      )}

      {FINANCE_INJECTION_STATUS.includes(
        props.row.original.transaction_type
      ) && (
        <RequirePermission permissions='lti.finance.injections.update'>
          <Button
            href={`/finance/detail/edit/injection?financeId=${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>
      )}

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

const FinanceTable = () => {
  const {
    state: tableFilterState,
    updateFilter,
    setPage,
    setPageSize,
    toQueryString: getTableFilterQueryString,
  } = useTableFilter({
    initial: {
      search: '',
      transactionType: '',
      bankId: '',
      partyType: '',
      sortBy: '',
      startDate: '',
      endDate: '',
    },
    paramMap: {
      page: 'page',
      pageSize: 'limit',
      transactionType: 'transaction_type',
      bankId: 'bank_id',
      partyType: 'party_type',
      sortBy: 'sort_date',
      startDate: 'start_date',
      endDate: 'end_date',
    },
  });

  // ===== State =====
  const [searchParams, setSearchParams] = useSearchParams();
  const deleteModal = useModal();
  const [pendingFilters, setPendingFilters] = useState({
    search: '',
    transactionType: '',
    bankId: '',
    partyType: '',
    sortBy: '',
    startDate: '',
    endDate: '',
  });
  const [selectedTransactionType, setSelectedTransactionType] =
    useState<OptionType | null>(null);
  const [selectedBank, setSelectedBank] = useState<OptionType | null>(null);
  const [selectedPartyType, setSelectedPartyType] = useState<OptionType | null>(
    null
  );
  const [selectedSortBy, setSelectedSortBy] = useState<OptionType | null>(null);
  const [selectedFinance, setSelectedFinance] = useState<Finance | null>(null);
  const [isDeleteLoading, setIsDeleteLoading] = useState(false);

  // ===== Fetch Data =====
  const {
    data: finances,
    isLoading,
    mutate: refreshFinances,
  } = useSWR(
    `${FinanceApi.basePath}/transactions${getTableFilterQueryString()}`,
    FinanceApi.getAllFetcher
  );

  // ===== Options =====
  const transactionTypeOptions = useMemo(() => {
    return [
      { label: 'Transfer', value: 'TRANSFER' },
      { label: 'Cash', value: 'CASH' },
      { label: 'Card', value: 'CARD' },
      { label: 'Cheque', value: 'CHEQUE' },
      { label: 'Saldo', value: 'SALDO' },
    ];
  }, []);
  const partyTypeOptions = useMemo(() => {
    return [
      { label: 'Customer', value: 'CUSTOMER' },
      { label: 'Supplier', value: 'SUPPLIER' },
    ];
  }, []);
  const sortByOptions = useMemo(() => {
    return [
      { label: 'Tanggal Pembayaran', value: 'payment_date' },
      { label: 'Tanggal Dibuat', value: 'created_at' },
    ];
  }, []);
  const {
    options: bankOptions,
    rawData: bankRawData,
    setInputValue: bankInputValue,
    loadMore: bankLoadMore,
  } = useSelect<Bank>(BankApi.basePath, 'id', 'alias');

  // ===== Handler =====
  const searchChangeHandler: ChangeEventHandler<HTMLInputElement> = (e) => {
    setPendingFilters((prev) => ({ ...prev, search: e.target.value }));
  };
  const transactionTypeChangeHandler = (
    val: OptionType | OptionType[] | null
  ) => {
    setSelectedTransactionType(val as OptionType);
    setPendingFilters((prev) => ({
      ...prev,
      transactionType: val ? ((val as OptionType).value as string) : '',
    }));
  };
  const bankChangeHandler = (val: OptionType | OptionType[] | null) => {
    setSelectedBank(val as OptionType);
    setPendingFilters((prev) => ({
      ...prev,
      bankId: val ? ((val as OptionType).value as string) : '',
    }));
  };
  const partyTypeChangeHandler = (val: OptionType | OptionType[] | null) => {
    setSelectedPartyType(val as OptionType);
    setPendingFilters((prev) => ({
      ...prev,
      partyType: val ? ((val as OptionType).value as string) : '',
    }));
  };
  const sortByChangeHandler = (val: OptionType | OptionType[] | null) => {
    setSelectedSortBy(val as OptionType);
    setPendingFilters((prev) => ({
      ...prev,
      sortBy: val ? ((val as OptionType).value as string) : '',
    }));
  };
  const startDateChangeHandler: ChangeEventHandler<HTMLInputElement> = (e) => {
    setPendingFilters((prev) => ({ ...prev, startDate: e.target.value }));
  };
  const endDateChangeHandler: ChangeEventHandler<HTMLInputElement> = (e) => {
    setPendingFilters((prev) => ({ ...prev, endDate: e.target.value }));
  };
  const pageSizeChangeHandler = (val: OptionType | OptionType[] | null) => {
    const newVal = val as OptionType;
    setPageSize(newVal.value as number);
  };
  const submitFilterHandler = () => {
    updateFilter('search', pendingFilters.search);
    updateFilter('transactionType', pendingFilters.transactionType);
    updateFilter('bankId', pendingFilters.bankId);
    updateFilter('partyType', pendingFilters.partyType);
    updateFilter('sortBy', pendingFilters.sortBy);
    updateFilter('startDate', pendingFilters.startDate);
    updateFilter('endDate', pendingFilters.endDate);
  };
  const resetFilterHandler = () => {
    setSelectedTransactionType(null);
    setSelectedBank(null);
    setSelectedPartyType(null);
    setSelectedSortBy(null);

    const emptyFilters = {
      search: '',
      transactionType: '',
      bankId: '',
      partyType: '',
      sortBy: '',
      startDate: '',
      endDate: '',
    };
    setPendingFilters(emptyFilters);

    updateFilter('search', '');
    updateFilter('transactionType', '');
    updateFilter('bankId', '');
    updateFilter('partyType', '');
    updateFilter('sortBy', '');
    updateFilter('startDate', '');
    updateFilter('endDate', '');
  };
  const confirmationModalDeleteClickHandler = async () => {
    setIsDeleteLoading(true);

    await FinanceApi.delete(selectedFinance?.id as number);
    refreshFinances();

    deleteModal.closeModal();
    toast.success('Successfully delete Finance!');
    setIsDeleteLoading(false);
  };

  const columns = useMemo(() => {
    return [
      {
        header: 'ID',
        accessorKey: 'payment_code',
      },
      {
        header: 'References Number',
        accessorKey: 'reference_number',
        cell: (props: CellContext<Finance, unknown>) => {
          const value = props.row.original.reference_number;
          return <span>{value ?? '-'}</span>;
        },
      },
      {
        header: 'Jenis Transaksi',
        accessorKey: 'transaction_type',
        cell: (props: CellContext<Finance, unknown>) => {
          const value = props.row.original.transaction_type
            .split('_')
            .join(' ');
          return <span>{formatTitleCase(value)}</span>;
        },
      },
      {
        header: 'Pihak',
        accessorFn: (finance: Finance) => finance.party.name,
        cell: (props: CellContext<Finance, unknown>) => {
          if (props.row.original.party.id) {
            return <span>{props.row.original.party.name}</span>;
          }
          return <span>{'-'}</span>;
        },
      },
      {
        header: 'Tanggal',
        accessorFn: (finance: Finance) =>
          formatDate(finance.payment_date, 'DD MMM YYYY'),
      },
      {
        header: 'Metode Pembayaran',
        accessorKey: 'payment_method',
        cell: (props: CellContext<Finance, unknown>) => {
          const value = props.row.original.payment_method.split('_').join(' ');
          return <span>{formatTitleCase(value)}</span>;
        },
      },
      {
        header: 'Bank',
        accessorFn: (finance: Finance) =>
          `${finance.bank.alias} - ${finance.bank.account_number} - ${finance.bank.owner}`,
      },
      {
        header: 'Pengeluaran (Rp)',
        accessorFn: (finance: Finance) =>
          formatCurrency(finance.expense_amount),
      },
      {
        header: 'Pemasukan (Rp)',
        accessorFn: (finance: Finance) => formatCurrency(finance.income_amount),
      },
      {
        header: 'Aksi',
        cell: (props: CellContext<Finance, unknown>) => {
          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 - 2;

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

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

              {currentPageSize <= 2 && (
                <RowCollapseOptions>
                  <RowOptionsMenu
                    type='collapse'
                    props={props}
                    deleteClickHandler={deleteClickHandler}
                  />
                </RowCollapseOptions>
              )}
            </>
          );
        },
      },
    ];
  }, []);
  return (
    <section className='size-full p-6 flex flex-col gap-6'>
      <div className='flex justify-end gap-2'>
        <RequirePermission permissions='lti.finance.injections.create'>
          <Button
            color='warning'
            className='min-w-24'
            href='/finance/add/injection'
          >
            Injection Saldo Bank
          </Button>
        </RequirePermission>
        <RequirePermission permissions='lti.finance.initial_balances.create'>
          <Button
            color='info'
            className='text-white min-w-24'
            href='/finance/add/initial-balance'
          >
            Saldo Awal
          </Button>
        </RequirePermission>
        <RequirePermission permissions='lti.finance.payments.create'>
          <Button color='primary' className='min-w-24' href='/finance/add'>
            Tambah
          </Button>
        </RequirePermission>
      </div>
      <Card
        variant='bordered'
        className={{
          wrapper: 'w-full',
        }}
        footer={
          <div className='flex justify-end gap-2'>
            <Button
              color='warning'
              className='min-w-24'
              onClick={resetFilterHandler}
            >
              Reset
            </Button>
            <Button
              color='primary'
              className='min-w-24'
              onClick={submitFilterHandler}
            >
              Cari
            </Button>
          </div>
        }
      >
        <div className='grid grid-cols-4 gap-6'>
          <SelectInput
            options={transactionTypeOptions}
            label='Jenis Transaksi'
            value={selectedTransactionType}
            onChange={transactionTypeChangeHandler}
            isClearable
          />
          <SelectInput
            options={
              isResponseSuccess(bankRawData)
                ? bankOptions.map((bank) => ({
                    label:
                      bankRawData.data.find((data) => data.id === bank.value)
                        ?.alias +
                      ' - ' +
                      bankRawData.data.find((data) => data.id === bank.value)
                        ?.account_number +
                      ' - ' +
                      bankRawData.data.find((data) => data.id === bank.value)
                        ?.owner,
                    value: bank.value,
                  }))
                : []
            }
            label='Bank'
            value={selectedBank}
            onChange={bankChangeHandler}
            onInputChange={bankInputValue}
            onMenuScrollToBottom={bankLoadMore}
            isClearable
          />
          <SelectInput
            options={partyTypeOptions}
            label='Pihak'
            value={selectedPartyType}
            onChange={partyTypeChangeHandler}
            isClearable
          />
          <DebouncedTextInput
            name='search'
            label='Cari'
            placeholder='Cari'
            value={pendingFilters.search}
            onChange={searchChangeHandler}
          />
          <SelectInput
            options={sortByOptions}
            label='Urutkan Berdasarkan'
            value={selectedSortBy}
            onChange={sortByChangeHandler}
            isClearable
          />
          <DateInput
            name='startDate'
            label='Periode Tanggal (Mulai)'
            value={pendingFilters.startDate}
            onChange={startDateChangeHandler}
          />
          <DateInput
            name='endDate'
            label='Periode Tanggal (Akhir)'
            value={pendingFilters.endDate}
            onChange={endDateChangeHandler}
          />
        </div>
      </Card>
      <Table<Finance>
        data={isResponseSuccess(finances) ? finances.data : []}
        columns={columns}
        pageSize={tableFilterState.pageSize}
        page={tableFilterState.page}
        onPageChange={setPage}
        onPageSizeChange={setPageSize}
        totalItems={
          isResponseSuccess(finances) ? finances.meta?.total_results : 0
        }
        isLoading={isLoading}
      />
      <ConfirmationModal
        ref={deleteModal.ref}
        type='error'
        text={`Apakah anda yakin ingin menghapus data Finance ini (${selectedFinance?.payment_code})?`}
        secondaryButton={{
          text: 'Tidak',
        }}
        primaryButton={{
          text: 'Ya',
          color: 'error',
          isLoading: isDeleteLoading,
          onClick: confirmationModalDeleteClickHandler,
        }}
      />
    </section>
  );
};

export default FinanceTable;
