import styled, { css, ThemeProvider } from "styled-components";
import {
  selectionContext,
  isSelectingContext,
} from "../context/SelectionContext";
import { useCopy } from "../hooks/useCopy";
import { editingCellContext } from "../context/EditorContext";
import { usePaste } from "../hooks/usePaste";
import { IBulkEditProps } from "../IBulkEditProps";
import { PropsRefProvider } from "../context/PropsContext";
import { Headers } from "./Headers";
import { useUndo } from "../hooks/useUndo";
import React from "react";
import { hoveredCellContext } from "../context/hoveredCellContext";
import { ErrorTooltip } from "./ErrorTooltip";
import { Selection } from "./Selection";
import { Editor } from "./Editor";
import {
  viewportSizeContext,
  viewportStartContext,
} from "../context/ViewportContext";
import { Scroller } from "./Scroller";
import { Rows } from "./Rows";
import { stickyColumnContext } from "../context/StickyColumnContext";
import { defaultTheme } from "../defaultTheme";
import { ScrollerRefProvider } from "../context/ScrollerContext";

export const BulkEditor = <TRow, TChange, TError>(
  props: IBulkEditProps<TRow, TChange, TError>
) => (
  <ThemeProvider theme={props.theme ?? defaultTheme}>
    <PropsRefProvider props={props}>
      <selectionContext.Provider>
        <isSelectingContext.Provider>
          <hoveredCellContext.Provider>
            <editingCellContext.Provider>
              <viewportSizeContext.Provider>
                <viewportStartContext.Provider>
                  <stickyColumnContext.Provider>
                    <ScrollerRefProvider>
                      <TableContent {...props} />
                    </ScrollerRefProvider>
                  </stickyColumnContext.Provider>
                </viewportStartContext.Provider>
              </viewportSizeContext.Provider>
            </editingCellContext.Provider>
          </hoveredCellContext.Provider>
        </isSelectingContext.Provider>
      </selectionContext.Provider>
    </PropsRefProvider>
  </ThemeProvider>
);

const TableContent = <TRow, TChange, TError>({
  rows,
  columnProps,
  rowHeight,
  numStickyColumns,
  numUnselectableColumns,
  headers,
  errors,
  renderErrorTooltip,
}: IBulkEditProps<TRow, TChange, TError>) => {
  useCopy<TRow, TChange, TError>();
  usePaste<TRow, TChange, TError>();
  useUndo<TRow, TChange, TError>();

  return (
    <Scroller>
      <TableContainer
        columnData={columnProps}
        numRows={rows.length}
        rowHeight={rowHeight}
        $headers={headers}
      >
        <Selection
          numStickyColumns={numStickyColumns}
          headers={headers}
          rowHeight={rowHeight}
        />
        <Editor
          columnProps={columnProps}
          rows={rows}
          numHeaders={headers.length}
        />
        <Headers headers={headers} numStickyColumns={numStickyColumns} />
        <Rows
          rows={rows}
          columnProps={columnProps}
          numStickyColumns={numStickyColumns}
          numHeaders={headers.length}
          errors={errors}
          numUnselectableColumns={numUnselectableColumns}
        />
      </TableContainer>
      <ErrorTooltip renderErrorTooltip={renderErrorTooltip} errors={errors} />
    </Scroller>
  );
};

const TableContainer = styled.div<{
  columnData: { minWidth?: number; maxWidth?: number }[];
  numRows: number;
  rowHeight: number;
  $headers: { height: number }[];
}>`
  position: relative;
  display: grid;
  grid-template-columns: ${({ columnData }) =>
    columnData
      .map(
        ({ minWidth, maxWidth }) =>
          `minmax(${minWidth ? `${minWidth}px` : "max-content"}, ${
            maxWidth ? `${maxWidth}px` : "1fr"
          })`
      )
      .join(" ")};
  grid-template-rows: ${({ $headers }) =>
      $headers.map(({ height }) => `${height}px`).join(" ")} ${({
      numRows,
      rowHeight,
    }) => (numRows ? css`repeat(${numRows}, ${rowHeight}px)` : null)};
  user-select: none;
  min-width: ${({ columnData }) =>
    columnData.reduce((acc, { minWidth }) => acc + (minWidth ?? 0), 0)}px;
`;
