import {
  Grid,
  GridCellProps,
  GridColumn,
  GridColumnReorderEvent,
  GridColumnResizeEvent,
  GridFilterChangeEvent,
  GridHeaderSelectionChangeEvent,
  GridSelectionChangeEvent,
  GridSortChangeEvent,
  GridSortSettings,
  GridToolbar,
} from "@progress/kendo-react-grid";

import {
  CompositeFilterDescriptor,
  DataResult,
  GroupDescriptor,
  SortDescriptor,
} from "@progress/kendo-data-query";
import FilterCell from "./FilterCell";
import GridCellFactory from "./GridCellFactory";
import { ReactElement, useCallback, useMemo } from "react";
import { CellType } from "./types";
import DropDownWidget from "../Dropdown";
import { SelectDescriptor } from "@progress/kendo-react-data-tools";

export type Action = {
  label: string;
  value: string;
} & {
  refresh: boolean;
  actionName: string;
  targetScreenDataField: string;
};
export type HeaderActionBarType = { actions: Action[] };

type GridViewProps = {
  dataItemKey?: string | undefined;
  id?: string | number;
  widgetStyle?: {
    id?: string;
    className?: string;
    inline?: React.CSSProperties;
  };
  data: DataResult;
  sortable?: boolean | GridSortSettings;
  sort?: SortDescriptor[];
  filterable?: boolean;
  filter?: CompositeFilterDescriptor;
  groupable?: boolean | undefined;
  group?: GroupDescriptor[];
  selectedField?: string;
  columns?: any[];
  headerActionBar?: HeaderActionBarType;
  selectedCount: number;
  select: SelectDescriptor;
  onFilterChange: (event: GridFilterChangeEvent) => void;
  onSelectionChange: (event: GridSelectionChangeEvent) => void;
  onHeaderSelectionChange: (event: GridHeaderSelectionChangeEvent) => void;
  onColumnResize: (event: GridColumnResizeEvent) => void;
  onColumnReorder: (event: GridColumnReorderEvent) => void;
  onSortChange: (event: GridSortChangeEvent) => void;
  onLocalSearchChange: any;
  columnSearchValues: CompositeFilterDescriptor;
  onAllMarked: () => void;
  onAllUnmarked: () => void;
  handleClick: (props: any, e: any) => void;
  handleHeaderAction: (
    callBack: any,
    screenDataField: string,
    action: Action,
    event: any
  ) => void;
};

const GridWidgetView = ({
  headerActionBar,
  columns,
  widgetStyle,
  onLocalSearchChange,
  columnSearchValues,
  selectedCount,
  groupable,
  select,
  onAllMarked,
  onAllUnmarked,
  handleClick,
  handleHeaderAction,
  ...rest
}: GridViewProps) => {
  const { data, selectedField } = rest;

  const renderToolbar = useMemo(
    () => (
      <GridToolbar>
        <div className="prc-grid-toolbar">
          You have selected {selectedCount} item{selectedCount === 1 ? "" : "s"}
          .
          {data.total !== selectedCount && (
            <span className="prc-grid-toolbar__select" onClick={onAllMarked}>
              {`Select all ${data.total} item${data.total === 1 ? "" : "s"
                } in the grid`}
            </span>
          )}
          {data.total === selectedCount && (
            <span
              onClick={onAllUnmarked}
              className="prc-grid-toolbar__unselect"
            >
              {`Unselect all ${selectedCount} item${selectedCount === 1 ? "" : "s"
                } from grid`}
            </span>
          )}
          <span className="prc-grid-toolbar__clear" onClick={onAllUnmarked}>
            (clear selection)
          </span>
        </div>
        <DropDownWidget
          onChange={handleHeaderAction}
          listData={headerActionBar?.actions}
          dataItemKey="value"
          textField="label"
        />
      </GridToolbar>
    ),
    [selectedCount, data.total, onAllMarked, onAllUnmarked, handleHeaderAction, headerActionBar?.actions]
  );

  // Create a custom cell renderer function
  const CustomCellRenderer: React.FC<GridCellProps> = (props) => {
    const fieldToCellType = Object.fromEntries(
      columns?.map((col) => [col.field, col.cellType]) ?? []
    );
    const cellType = fieldToCellType[props.field ?? ""];
    const isValidCellType = Object.values(CellType).includes(
      cellType as CellType
    );

    if (isValidCellType) {
      const cellWidget = GridCellFactory({
        cellProps: props,
        handleClick: handleClick,
        cellType: cellType
      });
      if (cellWidget) return cellWidget;
    }

    // Return default rendering for the cell
    return <td>{props.dataItem[props.field || ""]}</td>;
  };

  return (
    <Grid
      {...rest}
      selectable={{
        enabled: true,
        mode: "multiple",
        drag: false,
        cell: false,
      }}
      groupable={groupable ? { enabled: true } : false}
      id={widgetStyle?.id || ""}
      className={widgetStyle?.className || ""}
      style={widgetStyle?.inline || {}}
      reorderable={true}
      resizable={true}
      select={select}
    >
      {selectedCount > 0 && renderToolbar}
      {selectedField && <GridColumn columnType="checkbox" orderIndex={0} field={selectedField} filterable={false} sortable={false} locked={true} />}
      {columns?.map((column: any) => {
        return (
          <GridColumn
            key={column.id}
            field={column.field}
            title={column.title}
            width={column.width}
            sortable={column.sortable}
            headerSelectionValue={
              data.total > 0 && data.total === selectedCount
            }
            resizable={column.resizable}
            reorderable={column.primary ? false : column.reorderable}
            format={column.format}
            minResizableWidth={column.minResizableWidth ?? 25}
            orderIndex={column.primary ? 0 : column.order}
            locked={column.primary ? true : column.locked}
            filterable={false}
            filter={column.filter}
            className={column.widgetStyle?.className}
            id={column.id}
            cells={{ data: CustomCellRenderer }}
            columnMenu={column.filterable ? (filterProps) => (
              <FilterCell
                {...filterProps}
                onLocalSearchChange={onLocalSearchChange}
                columnSearchValues={columnSearchValues}
              />
            ) : undefined}
          // Use the cells prop for custom cell rendering if available
          // If not, we'll handle cell rendering at the Grid level
          />
        );
      })}
    </Grid>
  );
};

export default GridWidgetView;