import { Meta } from "@storybook/react";
import { TreeListProps } from "./TreeListProps";
import TreeList from "./TreeList";

import {
  orderBy as KendoOrderBy,
  filterBy as KendoFilterBy,
  mapTree as KendoMapTree,
  extendDataItem as KendoExtendDataItem,
  TreeListColumnProps as KendoTreeListColumnProps,
  TreeListTextFilter as KendoTreeListTextFilter,
  TreeListNumericFilter as KendoTreeListNumericFilter,
  TreeListDateFilter as KendoTreeListDateFilter,
  TreeListBooleanFilter as KendoTreeListBooleanFilter,
  TreeListExpandChangeEvent as KendoTreeListExpandChangeEvent,
  TreeListDataStateChangeEvent as KendoTreeListDataStateChangeEvent,
} from "@progress/kendo-react-treelist";
import employees from "./mockData/data";
import { Employee, DataState } from "./mockData/interfaces";
import React, { useState } from "react";

const subItemsField: string = "employees";
const expandField: string = "expanded";
const columns: KendoTreeListColumnProps[] = [
  {
    field: "name",
    title: "Name",
    width: "250px",
    filter: KendoTreeListTextFilter,
    expandable: true,
  },
  {
    field: "hireDate",
    title: "Hire Date",
    width: "200px",
    format: "{0:d}",
    filter: KendoTreeListDateFilter,
  },
  {
    field: "timeInPosition",
    title: "Year(s) in Position",
    width: "200px",
    filter: KendoTreeListNumericFilter,
  },
  {
    field: "fullTime",
    title: "Full Time",
    width: "100px",
    filter: KendoTreeListBooleanFilter,
  },
];

interface AppState {
  data: Employee[];
  dataState: DataState;
  expanded: number[];
}

export default {
  title: "Design System/TreeList",
  component: TreeList,
  tags: ["autodocs"],
  parameters: {
    docs: {
      description: {
        component:
          'The KendoReact TreeList enables the display of self-referencing tabular data and allows sorting, filtering, and data editing. \n\n```javascript\nimport { TreeList } from "@renault-ui-library"\n```',
      },
    },
  },
  argTypes: {
    dataTestId: {
      control: { type: "text" },
      description: "Specifies the data-test-id attribute for testing purposes.",
    },
    className: {
      control: { type: "text" },
      description: "Sets custom CSS classes to the TreeList DOM element.",
    },
    columnMenu: {
      control: { type: "object" },
      description: "Column menu component.",
    },
    columnMenuFilter: {
      control: { type: "object" },
      description: "Column menu filter.",
    },
    columns: {
      control: { type: "object" },
      description: "A collection of TreeListColumnProps for creating columns.",
    },
    columnVirtualization: {
      control: { type: "boolean" },
      description: "Enables the virtualization of the columns.",
    },
    data: {
      control: { type: "object" },
      description: "Sets the data of the TreeList.",
    },
    dataItemKey: {
      control: { type: "text" },
      description:
        "Sets the TreeList row key prop to the value of this field in the dataItem.",
    },
    editField: {
      control: { type: "text" },
      description:
        "Specifies the name of the field which will provide a Boolean representation of the edit state of the current item.",
    },
    editRow: {
      control: { type: "object" },
      description:
        "If set and when the data item is in edit mode, the editRow value will be rendered.",
    },
    expandField: {
      control: { type: "text" },
      description:
        "Specifies the name of the field which will provide a Boolean representation of the expanded state of the item.",
    },
    filter: {
      control: { type: "object" },
      description: "The descriptors by which the data is filtered.",
    },
    filterRow: {
      control: { type: "object" },
      description:
        "If set, it will be rendered instead of the default FilterRow TreeList component.",
    },
    navigatable: {
      control: { type: "boolean" },
      description:
        "If set to true, the user can use dedicated shortcuts to interact with the TreeList.",
    },
    noRecords: {
      control: { type: "object" },
      description:
        "Represents the component that will be rendered when the data property of the TreeList is empty or undefined.",
    },
    pager: {
      control: { type: "object" },
      description: "The pager component that the TreeList will render.",
    },
    reorderable: {
      control: { type: "boolean" },
      description:
        "If set to true, the user can reorder columns by dragging their header cells.",
    },
    resizable: {
      control: { type: "boolean" },
      description:
        "If set to true, the user can resize columns by dragging the edges of their header cells.",
    },
    row: {
      control: { type: "object" },
      description: "The TreeList row component.",
    },
    rowDraggable: {
      control: { type: "boolean" },
      description: "If set to true, the user can drag and drop rows.",
    },
    rowHeight: {
      control: { type: "number" },
      description:
        "Defines the row height and implements equal heights for all rows.",
    },
    scrollable: {
      control: { type: "text" },
      description: "Defines the scroll mode of the TreeList.",
    },
    selectable: {
      control: { type: "object" },
      description: "The TreeList selectable settings.",
    },
    selectedField: {
      control: { type: "text" },
      description:
        "Specifies the name of the field which will provide a Boolean representation of the selected state of the item.",
    },
    skip: {
      control: { type: "number" },
      description: "The number of records that will be skipped.",
    },
    sort: {
      control: { type: "object" },
      description: "The descriptors by which the data is sorted.",
    },
    sortable: {
      control: { type: "object" },
      description: "Enables sorting.",
    },
    style: {
      control: { type: "object" },
      description: "Represents the style HTML attribute.",
    },
    subItemsField: {
      control: { type: "text" },
      description:
        "Specifies the name of the field which will provide an array representation of the item subitems.",
    },
    tableProps: {
      control: { type: "object" },
      description:
        "A props object that will be passed to the underlying HTML table.",
    },
    take: {
      control: { type: "number" },
      description: "The number of records that will be taken.",
    },
    toolbar: {
      control: { type: "object" },
      description: "Represents the TreeList toolbar component.",
    },
    cellRender: {
      control: { type: "function" },
      description: "Fires when a cell is about to be rendered.",
    },
    headerCellRender: {
      control: { type: "function" },
      description: "Fires when a header cell is about to be rendered.",
    },
    onColumnMenuFilterChange: {
      control: { type: "function" },
      description: "Fires when the column menu filter changes.",
    },
    onColumnReorder: {
      control: { type: "function" },
      description: "Fires when the columns are reordered.",
    },
    onColumnResize: {
      control: { type: "function" },
      description: "Fires when a column is resized.",
    },
    onDataStateChange: {
      control: { type: "function" },
      description: "Fires when the data state changes.",
    },
    onExpandChange: {
      control: { type: "function" },
      description: "Fires when the expand state changes.",
    },
    onFilterChange: {
      control: { type: "function" },
      description: "Fires when the filter changes.",
    },
    onHeaderSelectionChange: {
      control: { type: "function" },
      description: "Fires when the header selection changes.",
    },
    onItemChange: {
      control: { type: "function" },
      description: "Fires when an item changes.",
    },
    onKeyDown: {
      control: { type: "function" },
      description: "Fires when a key is pressed down.",
    },
    onPageChange: {
      control: { type: "function" },
      description: "Fires when the page changes.",
    },
    onRowClick: {
      control: { type: "function" },
      description: "Fires when a row is clicked.",
    },
    onRowContextMenu: {
      control: { type: "function" },
      description: "Fires when the context menu is triggered on a row.",
    },
    onRowDoubleClick: {
      control: { type: "function" },
      description: "Fires when a row is double-clicked.",
    },
    onRowDrag: {
      control: { type: "function" },
      description: "Fires when a row is dragged.",
    },
    onRowDrop: {
      control: { type: "function" },
      description: "Fires when a row is dropped.",
    },
    onSelectionChange: {
      control: { type: "function" },
      description: "Fires when the selection changes.",
    },
    onSortChange: {
      control: { type: "function" },
      description: "Fires when the sort order changes.",
    },
    rowRender: {
      control: { type: "function" },
      description: "Fires when a row is about to be rendered.",
    },
  },
} as Meta;

export const Default = (args: TreeListProps): JSX.Element => {
  const [state, setState] = useState<AppState>({
    data: [...employees],
    dataState: {
      sort: [{ field: "name", dir: "asc" }],
      filter: [],
    },
    expanded: [1, 2, 32],
  });

  const onExpandChange = (e: KendoTreeListExpandChangeEvent) => {
    setState({
      ...state,
      expanded: e.value
        ? state.expanded.filter((id) => id !== e.dataItem.id)
        : [...state.expanded, e.dataItem.id],
    });
  };

  const handleDataStateChange = (event: KendoTreeListDataStateChangeEvent) => {
    const newDataState: DataState = {
      sort: event.dataState.sort || [],
      filter: event.dataState.filter || [],
    };

    setState({
      ...state,
      dataState: newDataState,
    });
  };

  const addExpandField = (dataTree: Employee[]): Employee[] => {
    const expanded: number[] = state.expanded;
    return KendoMapTree(dataTree, subItemsField, (item) =>
      KendoExtendDataItem(item, subItemsField, {
        [expandField]: expanded.includes(item.id),
      })
    );
  };

  const processData = () => {
    let { data, dataState } = state;
    let filteredData: Employee[] = KendoFilterBy(
      data,
      dataState.filter,
      subItemsField
    );
    let sortedData: Employee[] = KendoOrderBy(
      filteredData,
      dataState.sort,
      subItemsField
    );
    return addExpandField(sortedData);
  };

  return (
    <TreeList
      style={args.style}
      expandField={args.expandField}
      subItemsField={args.subItemsField}
      onExpandChange={onExpandChange}
      sortable={args.sortable}
      {...state.dataState}
      data={processData()}
      onDataStateChange={handleDataStateChange}
      columns={args.columns}
    />
  );
};

Default.args = {
  dataTestId: "treelist-data-testid",
  style: { maxHeight: "600px", overflow: "auto" },
  expandField: expandField,
  subItemsField: subItemsField,
  sortable: { mode: "multiple" },
  columns: columns,
};
