import type { Info1D, Peak1D } from '@zakodium/nmr-types';
import dlv from 'dlv';
import { memo, useCallback, useMemo, useState } from 'react';
import { FaEdit, FaRegTrashAlt } from 'react-icons/fa';
import type { CellProps } from 'react-table';

import { useDispatch } from '../../context/DispatchContext.js';
import { EditableColumn } from '../../elements/EditableColumn.js';
import { EmptyText } from '../../elements/EmptyText.js';
import ReactTable from '../../elements/ReactTable/ReactTable.js';
import type { ControlCustomColumn } from '../../elements/ReactTable/utility/addCustomColumn.js';
import addCustomColumn, {
  createActionColumn,
} from '../../elements/ReactTable/utility/addCustomColumn.js';
import { usePanelPreferences } from '../../hooks/usePanelPreferences.js';
import { EditPeakShapeModal } from '../../modal/EditPeakShapeModal.js';
import { formatNumber } from '../../utility/formatNumber.js';
import { NoDataForFid } from '../extra/placeholder/NoDataForFid.js';

import type { PeakRecord } from './PeaksPanel.js';

interface PeaksTableProps {
  activeTab: string;
  data: PeakRecord[];
  info: Info1D;
}

function handleActiveRow(row: any) {
  return row.original.isConstantlyHighlighted;
}

function PeaksTable(props: PeaksTableProps) {
  const { activeTab, data, info } = props;
  const dispatch = useDispatch();
  const peaksPreferences = usePanelPreferences('peaks', activeTab);
  const [peak, setEditedPeak] = useState<Peak1D | undefined>();

  const deletePeakHandler = useCallback(
    (row: any) => {
      const params = row.original;
      dispatch({
        type: 'DELETE_PEAK',
        payload: { id: params.id },
      });
    },
    [dispatch],
  );
  const editPeakHandler = useCallback((row: any) => {
    setEditedPeak(row.original);
  }, []);

  const saveDeltaPPMRefsHandler = useCallback(
    (event: any, row: any) => {
      const shift =
        Number.parseFloat(event.target.value) - Number.parseFloat(row.x);
      dispatch({ type: 'SHIFT_SPECTRUM', payload: { shift } });
    },
    [dispatch],
  );
  const COLUMNS = useMemo<Array<ControlCustomColumn<PeakRecord>>>(
    () => [
      {
        showWhen: 'showSerialNumber',
        index: 1,
        Header: '#',
        accessor: (_, index) => index + 1,
        style: { width: '1%', maxWidth: '40px', minWidth: '40px' },
      },
      {
        showWhen: 'deltaPPM.show',
        index: 3,
        Header: 'δ (ppm)',
        accessor: 'x',
        Cell: ({ row }: CellProps<PeakRecord>) => (
          <EditableColumn
            value={formatNumber(
              row.original.x,
              peaksPreferences.deltaPPM.format,
            )}
            onSave={(event) => saveDeltaPPMRefsHandler(event, row.original)}
            type="number"
            validate={(val) => val !== ''}
          />
        ),
      },
      {
        showWhen: 'deltaHz.show',
        index: 4,
        Header: 'δ (Hz)',
        accessor: 'xHz',
        Cell: ({ row }: CellProps<PeakRecord>) =>
          formatNumber(row.original.xHz, peaksPreferences.deltaHz.format),
      },
      {
        showWhen: 'intensity.show',
        index: 5,
        Header: 'Intensity',
        style: { maxWidth: '80px' },
        accessor: 'y',
        Cell: ({ row }: CellProps<PeakRecord>) =>
          formatNumber(row.original.y, peaksPreferences.intensity.format),
      },
      {
        showWhen: 'peakWidth.show',
        index: 6,
        Header: 'Width (Hz)',
        accessor: 'width',
        Cell: ({ row }: CellProps<PeakRecord>) =>
          formatNumber(row.original.width, peaksPreferences.peakWidth.format),
      },
      {
        showWhen: 'showKind',
        index: 7,
        Header: 'Kind',
        accessor: (row) => row.shape?.kind || '',
      },
      {
        showWhen: 'fwhm.show',
        index: 8,
        Header: 'fwhm',
        accessor: (row) => row?.shape?.fwhm || '',
        Cell: ({ row }: CellProps<PeakRecord>) => {
          const fwhm = row.original?.shape?.fwhm;
          if (fwhm) {
            return formatNumber(fwhm, peaksPreferences.fwhm.format);
          }
          return '';
        },
      },
      {
        showWhen: 'mu.show',
        index: 9,
        Header: 'mu',
        accessor: (row) =>
          (row?.shape?.kind === 'pseudoVoigt' && row?.shape?.mu) || '',
        Cell: ({ row }: CellProps<PeakRecord>) => {
          const mu =
            row.original?.shape?.kind === 'pseudoVoigt' &&
            row.original?.shape?.mu;
          if (mu) {
            return formatNumber(mu, peaksPreferences.mu.format);
          }
          return '';
        },
      },
      {
        showWhen: 'gamma.show',
        index: 9,
        Header: 'gamma',
        accessor: (row) =>
          (row?.shape?.kind === 'generalizedLorentzian' && row?.shape?.gamma) ||
          '',
        Cell: ({ row }: CellProps<PeakRecord>) => {
          const gamma =
            row.original?.shape?.kind === 'generalizedLorentzian' &&
            row.original?.shape?.gamma;
          if (gamma) {
            return formatNumber(gamma, peaksPreferences.gamma.format);
          }
          return '';
        },
      },
      {
        showWhen: 'showEditPeakShapeAction',
        ...createActionColumn<PeakRecord>({
          index: 20,
          icon: <FaEdit />,
          onClick: editPeakHandler,
          style: {
            borderRight: '0px',
          },
        }),
      },
      {
        showWhen: 'showDeleteAction',
        ...createActionColumn<PeakRecord>({
          index: 21,
          icon: <FaRegTrashAlt />,
          onClick: deletePeakHandler,
        }),
      },
    ],
    [
      peaksPreferences,
      saveDeltaPPMRefsHandler,
      deletePeakHandler,
      editPeakHandler,
    ],
  );

  const tableColumns = useMemo(() => {
    const columns: Array<ControlCustomColumn<PeakRecord>> = [];
    for (const col of COLUMNS) {
      const { showWhen, ...colParams } = col;
      if (dlv(peaksPreferences, showWhen)) {
        addCustomColumn(columns, colParams);
      }
    }

    columns.sort((object1, object2) => object1.index - object2.index);
    return columns;
  }, [COLUMNS, peaksPreferences]);

  if (info?.isFid) {
    return <NoDataForFid />;
  }

  if (data.length === 0) {
    return <EmptyText text="No data" />;
  }

  return (
    <>
      <EditPeakShapeModal
        peak={peak}
        onCloseDialog={() => setEditedPeak(undefined)}
      />
      <ReactTable
        activeRow={handleActiveRow}
        rowStyle={{ activated: { backgroundColor: '#f5f5dc' } }}
        data={data}
        columns={tableColumns}
        approxItemHeight={24}
        enableVirtualScroll
      />
    </>
  );
}

export default memo(PeaksTable);
