import { render } from "@testing-library/react";
import React, { useEffect, useRef, useState } from "react";
import { useUndoStack } from "../..";
import { BulkEditor } from "../../..";
import { useSubRowProps } from "../../subRows";

type ISubRow = { key: string; data: string[] };
type IElement = { key: string; subRows: ISubRow[] };

const TextEditor = ({
  value,
  onChange,
  onBlur,
}: {
  value: string;
  onChange: (value: string) => void;
  onBlur: () => void;
}) => {
  const [localValue, setLocalValue] = useState(value);
  const localValueRef = useRef(value);
  localValueRef.current = localValue;
  useEffect(() => () => onChange(localValueRef.current), []);
  return (
    <input
      autoFocus
      value={localValue}
      onChange={(e) => setLocalValue(e.target.value)}
      onBlur={onBlur}
    />
  );
};

const update = (
  element: IElement,
  subRow: ISubRow,
  column: number,
  value: string
) => {
  const newSubRows = [...element.subRows];
  const subRowIndex = element.subRows.findIndex((sr) => sr.key === subRow.key);
  const newData = [...newSubRows[subRowIndex].data];
  newData[column] = value;
  newSubRows[subRowIndex] = { ...newSubRows[subRowIndex], data: newData };
  return { ...element, subRows: newSubRows };
};

export const createTestTable = (numRows: number = 6) => {
  let outerRows = [...new Array(numRows)].map((_, n) => ({
    key: `row${n}`,
    subRows: [0, 1, 2].map((i) => ({
      key: `${i}`,
      data: ["a", "b", "c", "d", "e", "f"].map((c) => `${c}${n}.${i}`),
    })),
  }));
  const onChange = jest.fn();
  return {
    getRows: () => outerRows,
    render: () => {
      const Component = () => {
        const [rows, setRows] = useState(outerRows);

        const getKey = (row: { key: string }) => row.key;
        const propagateChange = (newRows: any[]) => {
          outerRows = newRows;
          onChange(newRows);
          setRows(newRows);
        };
        const { handleUndo, handleRedo, handleChange } = useUndoStack(
          rows,
          getKey,
          propagateChange
        );

        const tableProps = useSubRowProps<
          { key: string; subRows: { key: string; data: string[] }[] },
          { key: string; data: string[] },
          string,
          string
        >({
          elements: rows,
          createSubRows: (row) => row.subRows,
          areRowsEqual: (a, b) => a.key === b.key,
          getKey,
          columnProps: [0, 1, 2, 3, 4, 5].map((i) => ({
            key: `col${i}`,
            onClear: (row, subRow) => update(row, subRow, i, ""),
            onCopy: (_row, subRow) => subRow.data[i],
            onPaste: (row, subRow, value) => update(row, subRow, i, value),
            renderCell: ({ subRow }) => subRow.data[i],
            renderEditor: ({ element, subRow, onChange, onBlur }) => (
              <TextEditor
                value={subRow.data[i]}
                onChange={(val) => onChange(update(element, subRow, i, val))}
                onBlur={onBlur}
              />
            ),
          })),
          onChange: handleChange,
          onUndo: handleUndo,
          onRedo: handleRedo,
          rowHeight: 40,
          numStickyColumns: 0,
          numUnselectableColumns: 0,
          headers: [
            {
              height: 40,
              row: ["a", "b", "c", "d", "e", "f"].map((h) => ({
                key: h,
                component: h,
                columnSpan: 1,
              })),
            },
          ],
          renderErrorTooltip: (e) => e,
        });

        return <BulkEditor {...tableProps} />;
      };

      Object.defineProperty(HTMLElement.prototype, "clientHeight", {
        get: () => 400,
        configurable: true,
      });
      render(<Component />);
    },
  };
};
