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

type IRow = {
  key: string;
  data: string[];
};

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 = (row: IRow, column: number, value: string) => {
  const newData = [...row.data];
  newData[column] = value;
  return { ...row, data: newData };
};

export const testData: IBulkEditProps<
  { key: string; data: string[] },
  { key: string; data: string[] },
  string
> = {
  rows: [0, 1, 2, 3, 4, 5].map((n) => ({
    key: `row${n}`,
    data: ["a", "b", "c", "d", "e", "f"].map((c) => `${c}${n}`),
  })),
  errors: [0, 1, 2, 3, 4, 5].map(() => [0, 1, 2, 3, 4, 5].map(() => null)),
  onUndo: jest.fn(),
  onRedo: jest.fn(),
  onChange: jest.fn(),
  rowHeight: 40,
  numStickyColumns: 0,
  numUnselectableColumns: 0,
  renderErrorTooltip: (e) => e,
  applyPastes: (pastes) =>
    pastes.map(({ row, changers }) => {
      let newRow = row;
      changers.forEach((changer) => (newRow = changer(newRow)));
      return newRow;
    }),
  headers: [
    {
      height: 40,
      row: ["a", "b", "c", "d", "e", "f"].map((h) => ({
        key: h,
        component: h,
        columnSpan: 1,
      })),
    },
  ],
  columnProps: [0, 1, 2, 3, 4, 5].map((i) => ({
    key: `col${i}`,
    onClear: (row) => update(row, i, ""),
    onCopy: (row) => row.data[i],
    onPaste: (row, value) => update(row, i, value),
    renderCell: ({ row }) => row.data[i],
    renderEditor: ({ row, onChange, onBlur }) => (
      <TextEditor
        value={row.data[i]}
        onChange={(val) => onChange(update(row, i, val))}
        onBlur={onBlur}
      />
    ),
  })),
};

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

        const handleChange = (changes: { key: string; data: string[] }[]) => {
          const newRows = [...rows];
          changes.forEach((change) => {
            const index = rows.findIndex((row) => row.key === change.key);
            newRows[index] = change;
          });
          setRows(newRows);
          onChange(changes);
          outerRows = newRows;
        };

        return (
          <BulkEditor
            {...testData}
            rows={rows}
            onChange={handleChange}
            errors={[...new Array(numRows)].map(() =>
              [0, 1, 2, 3, 4, 5].map(() => null)
            )}
          />
        );
      };

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