/**
 * TEAM: frontend_infra
 *
 * @flow
 */

import * as React from "react";
import {css, StyleSheet} from "aphrodite";
import {storiesOf} from "@storybook/react";
import {array, boolean, withKnobs} from "@storybook/addon-knobs";
import {v4 as uuid} from "uuid";
import sections from "../sections";
import DeprecatedTable, {
  type ColumnDefinition,
} from "../../table/DeprecatedTable";
import Button from "../../button/Button";
import data from "../../table/__demo__/data.json";
import columnDefinitions from "../../table/__demo__/columnDefinitions";
import Text from "../../Text";
import NotificationModal from "../../modal/NotificationModal";
import StaticLoadingRow from "../../table/StaticLoadingRow";

const BasicTableHoist = knobProps => {
  const [sortBy, setSortBy] = React.useState({
    columnId: "id",
    direction: "asc",
  });

  return (
    <div className={css(styles.container)}>
      <Text weight="bold">
        NOTE: DeprecatedTable takes the full height of its container so the
        container needs to have an explicit height set
      </Text>
      <DeprecatedTable
        data={data.slice(0, 100)}
        columnDefinitions={columnDefinitions}
        getUniqueRowId={data => data.id}
        sortBy={sortBy}
        onSortByChange={setSortBy}
        {...knobProps}
      />
    </div>
  );
};

const LoadingTableHoist = knobProps => {
  const [sortBy, setSortBy] = React.useState({
    columnId: "id",
    direction: "asc",
  });

  return (
    <div className={css(styles.container)}>
      <DeprecatedTable
        data={data.slice(0, 100)}
        columnDefinitions={columnDefinitions}
        getUniqueRowId={data => data.id}
        sortBy={sortBy}
        onSortByChange={setSortBy}
        {...knobProps}
      />
    </div>
  );
};

const ColumnCustomizationHoist = knobProps => {
  const [hiddenColumns, setHiddenColumns] = React.useState([
    {columnId: "city"},
  ]);
  const [sortBy, setSortBy] = React.useState({
    columnId: "id",
    direction: "asc",
  });
  const pinnedColumns = [
    {
      columnId: "id",
      align: "left",
    },
  ];

  const table = (
    <DeprecatedTable
      data={data.slice(0, 100)}
      columnDefinitions={columnDefinitions}
      getUniqueRowId={data => data.id}
      columnCustomizationEnabled={true}
      hiddenColumns={hiddenColumns}
      onHiddenColumnsChange={setHiddenColumns}
      sortBy={sortBy}
      onSortByChange={setSortBy}
      pinnedColumns={pinnedColumns}
      {...knobProps}
    />
  );
  return <div className={css(styles.container)}>{table}</div>;
};

const RowClickingHoist = () => {
  const [clickedRow, setClickedRow] = React.useState(null);
  const [sortBy, setSortBy] = React.useState({
    columnId: "id",
    direction: "asc",
  });

  const table = (
    <DeprecatedTable
      data={data.slice(0, 100)}
      columnDefinitions={columnDefinitions}
      getUniqueRowId={data => data.id}
      sortBy={sortBy}
      onSortByChange={setSortBy}
      rowClickingEnabled={true}
      clickedRow={clickedRow}
      onRowClick={setClickedRow}
    />
  );
  return (
    <div className={css(styles.container)}>
      {table}
      {clickedRow ? (
        <NotificationModal
          title="Clicked Row"
          buttons={[]}
          onRequestClose={() => setClickedRow(null)}
        >
          <Text>You clicked the row with id {clickedRow}</Text>
        </NotificationModal>
      ) : null}
    </div>
  );
};

const RowSelectionHoist = ({
  disabledRows,
  hideSelectAllCheckbox,
  ...knobProps
}) => {
  const [selectedRows, setSelectedRows] = React.useState(new Set());
  const [sortBy, setSortBy] = React.useState({
    columnId: "id",
    direction: "asc",
  });

  const table = (
    <DeprecatedTable
      data={data.slice(0, 100)}
      columnDefinitions={columnDefinitions}
      getUniqueRowId={data => data.id}
      rowSelectionEnabled={true}
      selectedRows={selectedRows}
      onSelectedRowsChange={setSelectedRows}
      sortBy={sortBy}
      onSortByChange={setSortBy}
      disabledRows={new Set(disabledRows.map(Number))}
      hideSelectAllCheckbox={hideSelectAllCheckbox}
      {...knobProps}
    />
  );
  return <div className={css(styles.container)}>{table}</div>;
};

const RowAggregationHoist = knobProps => {
  const [expandedRows, setExpandedRows] = React.useState(new Set());
  const [sortBy, setSortBy] = React.useState({
    columnId: "id",
    direction: "asc",
  });

  const table = (
    <DeprecatedTable
      data={data.slice(0, 100)}
      columnDefinitions={columnDefinitions}
      getUniqueRowId={row => row.id}
      rowAggregationEnabled={true}
      rowAggregationPinned={false}
      getRowGroupId={row => row.network}
      expandedRows={expandedRows}
      expandSingleAggregateRow={true}
      onExpandedRowsChange={setExpandedRows}
      sortBy={sortBy}
      onSortByChange={setSortBy}
      {...knobProps}
    />
  );
  return <div className={css(styles.container)}>{table}</div>;
};

const RowAggregationSelectionHoist = ({
  disabledRows,
  hideSelectAllCheckbox,
  ...knobProps
}) => {
  const [expandedRows, setExpandedRows] = React.useState(new Set());
  const [selectedRows, setSelectedRows] = React.useState(new Set());

  const [sortBy, setSortBy] = React.useState({
    columnId: "id",
    direction: "asc",
  });

  const table = (
    <DeprecatedTable
      data={data.slice(0, 100)}
      columnDefinitions={columnDefinitions}
      getUniqueRowId={row => row.id}
      rowSelectionEnabled={true}
      selectedRows={selectedRows}
      onSelectedRowsChange={setSelectedRows}
      rowAggregationEnabled={true}
      getRowGroupId={row => row.network}
      expandedRows={expandedRows}
      onExpandedRowsChange={setExpandedRows}
      sortBy={sortBy}
      onSortByChange={setSortBy}
      disabledRows={new Set(disabledRows.map(Number))}
      hideSelectAllCheckbox={hideSelectAllCheckbox}
      {...knobProps}
    />
  );
  return <div className={css(styles.container)}>{table}</div>;
};

const PinnedColumnsHoist = () => {
  const [sortBy, setSortBy] = React.useState({
    columnId: "id",
    direction: "asc",
  });

  const table = (
    <DeprecatedTable
      data={data.slice(0, 100)}
      columnDefinitions={columnDefinitions}
      getUniqueRowId={data => data.id}
      pinnedColumns={[
        {columnId: "id", align: "left"},
        {columnId: "name", align: "left"},
        {columnId: "cta", align: "right"},
      ]}
      sortBy={sortBy}
      onSortByChange={setSortBy}
    />
  );
  return <div className={css(styles.container)}>{table}</div>;
};

const InfiniteLoadHoist = () => {
  const [sortBy, setSortBy] = React.useState({
    columnId: "id",
    direction: "asc",
  });
  const [sliceIndex, setSliceIndex] = React.useState<number>(100);
  const [isNextPageLoading, setNextPageLoading] = React.useState(false);
  const timeoutRef = React.useRef();
  const handleLoadNextPage = React.useCallback(() => {
    setNextPageLoading(true);
    timeoutRef.current = setTimeout(() => {
      setSliceIndex(index => index + 100);
      setNextPageLoading(false);
      clearTimeout(timeoutRef.current);
    }, 3000);
  }, [setSliceIndex, setNextPageLoading]);
  React.useEffect(
    () => () => {
      if (timeoutRef.current) clearTimeout(timeoutRef.current);
    },
    []
  );

  const table = (
    <DeprecatedTable
      data={data.slice(0, sliceIndex)}
      columnDefinitions={columnDefinitions}
      getUniqueRowId={data => data.id}
      sortBy={sortBy}
      onSortByChange={setSortBy}
      hasNextPage={sliceIndex < data.length}
      isNextPageLoading={isNextPageLoading}
      loadNextPage={handleLoadNextPage}
    />
  );
  return <div className={css(styles.container)}>{table}</div>;
};

const StaticLoadingRowHoist = () => {
  const [sortBy, setSortBy] = React.useState({
    columnId: "id",
    direction: "asc",
  });
  const [sliceIndex, setSliceIndex] = React.useState<number>(100);
  const [isNextPageLoading, setNextPageLoading] = React.useState(false);
  const timeoutRef = React.useRef();
  const handleLoadNextPage = React.useCallback(() => {
    setNextPageLoading(true);
    timeoutRef.current = setTimeout(() => {
      setSliceIndex(index => index + 100);
      setNextPageLoading(false);
      clearTimeout(timeoutRef.current);
    }, 3000);
  }, [setSliceIndex, setNextPageLoading]);
  React.useEffect(
    () => () => {
      if (timeoutRef.current) clearTimeout(timeoutRef.current);
    },
    []
  );

  const table = (
    <DeprecatedTable
      data={data.slice(0, sliceIndex)}
      columnDefinitions={columnDefinitions}
      getUniqueRowId={data => data.id}
      sortBy={sortBy}
      onSortByChange={setSortBy}
      hasNextPage={sliceIndex < data.length}
      staticLoadingRow={
        <StaticLoadingRow
          onLoadMoreClick={handleLoadNextPage}
          fetchedItemCount={sliceIndex}
          totalItemCount={data.length}
          isNextPageLoading={isNextPageLoading}
        />
      }
    />
  );
  return <div className={css(styles.container)}>{table}</div>;
};

function HelloCell({row}: {|+row: string|}) {
  React.useEffect(() => {
    // eslint-disable-next-line no-console
    console.log("HelloCell mounted");
  }, []);
  // eslint-disable-next-line no-console
  console.log("HelloCell rendered");

  return <div>Hello {row}</div>;
}

const MemoizedHelloCell = React.memo(HelloCell);

const memoizedColumns: $ReadOnlyArray<ColumnDefinition<string>> = [
  {
    id: "helloColumn",
    header: "Hello",
    render: row => <MemoizedHelloCell row={row} />,
    width: 100,
  },
];

const nonMemoizedColumns: $ReadOnlyArray<ColumnDefinition<string>> = [
  {
    id: "helloColumn",
    header: "Hello",
    render: row => <HelloCell row={row} />,
    width: 100,
  },
];

const memoData = ["row 1", "row 2", "row 3"];

function getUniqueRowId(row: string) {
  return row;
}

function RerenderTableTest() {
  const [memoize, setMemoize] = React.useState(false);
  const [, setUselessState] = React.useState(uuid);

  const columns = memoize ? memoizedColumns : nonMemoizedColumns;
  const triggerRerender = React.useCallback(() => {
    setUselessState(uuid());
  }, [setUselessState]);

  return (
    <div>
      <Button onClick={triggerRerender} label="Rerender" />
      <Button
        onClick={() => {
          setMemoize(!memoize);
        }}
        label={`Switch to ${memoize ? "non-memoized" : "memoized"}`}
      />

      <div style={{height: "200px", width: "200px"}}>
        <DeprecatedTable
          columnDefinitions={columns}
          data={memoData}
          getUniqueRowId={getUniqueRowId}
        />
      </div>
    </div>
  );
}

const getKnobs = ({isLoading = false} = {}) => ({
  isLoading: boolean("isLoading", isLoading),
  compactCells: boolean("compactCells", false),
  useFullWidth: boolean("useFullWidth", false),
  largeHeader: boolean("largeHeader", false),
});

const getDisableKnobs = () => ({
  disabledRows: array("disabledRows", []),
  hideSelectAllCheckbox: boolean("hideSelectAllCheckbox", false),
});

// $FlowFixMe[invalid-export]
const stories = storiesOf(`${sections.table}/DeprecatedTable`, module);
stories.addDecorator(withKnobs);

stories.add("Basic DeprecatedTable", () => <BasicTableHoist {...getKnobs()} />);
stories.add("Loading DeprecatedTable", () => (
  <LoadingTableHoist {...getKnobs({isLoading: true})} />
));
stories.add("Column Customization DeprecatedTable", () => (
  <ColumnCustomizationHoist {...getKnobs()} />
));
stories.add("Row Clicking DeprecatedTable", () => <RowClickingHoist />);
stories.add("Row Selection DeprecatedTable", () => (
  <RowSelectionHoist {...getDisableKnobs()} {...getKnobs()} />
));
stories.add("Row Aggregation DeprecatedTable", () => (
  <RowAggregationHoist {...getKnobs()} />
));
stories.add("Row Aggregation Selection DeprecatedTable", () => (
  <RowAggregationSelectionHoist {...getDisableKnobs()} {...getKnobs()} />
));
stories.add("Pinned Columns DeprecatedTable", () => <PinnedColumnsHoist />);
stories.add("Static Loading Row DeprecatedTable", () => (
  <StaticLoadingRowHoist />
));
stories.add("Infinite Load DeprecatedTable", () => <InfiniteLoadHoist />);
stories.add("Rerender DeprecatedTable Test", () => <RerenderTableTest />);

const styles = StyleSheet.create({
  container: {width: 900, height: 600},
});
