import {
  FilterAlt as FilterAltIcon,
  Functions as FunctionsIcon,
  GridOn as GridOnIcon,
  Numbers as NumbersIcon,
  Abc as AbcIcon,
} from '@mui/icons-material';

import { useState } from 'react';
import { AllLogicDescriptions, AllLogicMap, QueryElementTypes, SchemaReactflowLogicNode, toHandleData } from '../../model';
import { ConnectingNodeDataI } from '../utils/connectorDrop';
import { useQuerybuilderGraph } from '@graphpolaris/shared/lib/data-access';
import { toQuerybuilderGraphology, setQuerybuilderGraphology } from '@graphpolaris/shared/lib/data-access/store/querybuilderSlice';
import { useDispatch } from 'react-redux';
import { Button, Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from '../../..';

export const QueryBuilderLogicPillsPanel = (props: {
  reactFlowWrapper: HTMLDivElement | null;
  className?: string;
  title?: string;
  onClick: (item: AllLogicDescriptions) => void;
  onDrag?: (item: AllLogicDescriptions) => void;
  connection?: ConnectingNodeDataI | null;
  editNode?: SchemaReactflowLogicNode;
}) => {
  const graph = useQuerybuilderGraph();
  const dispatch = useDispatch();
  const graphologyGraph = toQuerybuilderGraphology(graph);
  const [selectedOp, setSelectedOp] = useState(-1);
  const [selectedType, setSelectedType] = useState(-1);

  let filterType = props.editNode
    ? props.editNode.data.logic.input.type
    : ((props.connection?.params?.handleId ? toHandleData(props.connection.params.handleId).attributeType : null) as string);
  if (!filterType) return <></>;
  else if (filterType === 'string') filterType = 'string';
  else if (filterType === 'int' || filterType === 'float') filterType = 'number';

  const dataOps = [
    {
      title: 'aggregation',
      description: 'Aggregation Functions',
      icon: <GridOnIcon fontSize="small" />,
    },
    {
      title: 'function',
      description: 'Math Functions',
      icon: <FunctionsIcon fontSize="small" />,
    },
    {
      title: 'filter',
      description: 'Filter Functions',
      icon: <FilterAltIcon fontSize="small" />,
    },
  ];
  const dataTypes = [
    {
      title: 'number',
      description: 'Number',
      icon: <NumbersIcon fontSize="small" />,
    },
    {
      title: 'string',
      description: 'Text',
      icon: <AbcIcon fontSize="small" />,
    },
  ].filter((item) => !filterType || item.title === filterType);

  const onDragStart = (event: React.DragEvent, value: AllLogicDescriptions) => {
    console.log('drag start');

    event.dataTransfer.setData('application/reactflow', JSON.stringify({ value }));
    event.dataTransfer.effectAllowed = 'move';
    if (props.onDrag) props.onDrag(value);
  };

  const onNewNodeFromPopup = (value: AllLogicDescriptions) => {
    const logic = AllLogicMap[value.key];

    if (props.connection === null || props.connection?.params?.handleId == null) {
      const bounds = props.reactFlowWrapper?.getBoundingClientRect() || { x: 0, y: 0, width: 0, height: 0 };

      const logicNode = graphologyGraph.addLogicPill2Graphology({
        name: value.name,
        type: QueryElementTypes.Logic,
        x: bounds.width / 2,
        y: bounds.height / 2,
        logic: logic,
      });
    } else {
      const params = props.connection.params;
      const position = props.connection.position;

      const logicNode = graphologyGraph.addLogicPill2Graphology({
        name: value.name,
        type: QueryElementTypes.Logic,
        x: position.x,
        y: position.y,
        logic: logic,
      });

      if (!logicNode?.id) throw new Error('Logic node has no id');
      if (!logicNode?.name) throw new Error('Logic node has no name');
      if (!params.handleId) throw new Error('Connection has no source or target');

      const sourceHandleData = toHandleData(params.handleId);
      graphologyGraph.addEdge2Graphology(
        graphologyGraph.getNodeAttributes(params.nodeId),
        graphologyGraph.getNodeAttributes(logicNode.id),
        { type: 'connection' },
        { sourceHandleName: sourceHandleData.attributeName, targetHandleName: logic.input.name },
      );
    }

    dispatch(setQuerybuilderGraphology(graphologyGraph));
    props.onClick(value);
  };

  const onEditNodeFromPopup = (value: AllLogicDescriptions) => {
    if (!props.editNode?.id) return;
    const logic = AllLogicMap[value.key];
    const edges = graphologyGraph
      .edges(props.editNode.id)
      .map((edge) => ({ id: edge, attributes: graphologyGraph.getEdgeAttributes(edge) }));
    console.log('edit node', props.editNode.data, edges);

    // graphologyGraph
    graphologyGraph.addLogicPill2Graphology({
      ...props.editNode.data,
      name: value.name,
      type: QueryElementTypes.Logic,
      logic: logic,
    });

    edges.forEach((edge, i) => {
      graphologyGraph.dropEdge(edge.id);

      if (i >= logic.numExtraInputs + 1) return; // ignore edges not present in new logic pill

      graphologyGraph.addEdge2Graphology(
        graphologyGraph.getNodeAttributes(edge.attributes.sourceHandleData.nodeId),
        graphologyGraph.getNodeAttributes(edge.attributes.targetHandleData.nodeId),
        { type: 'connection' },
        {
          sourceHandleName: edge.attributes.sourceHandleData.attributeName,
          targetHandleName: edge.attributes.targetHandleData.attributeName,
        },
      );
    });

    // graphologyGraph.addEdge2Graphology(
    //   graphologyGraph.getNodeAttributes(params.nodeId),
    //   graphologyGraph.getNodeAttributes(logicNode.id),
    //   { type: 'connection' },
    //   { sourceHandleName: sourceHandleData.attributeName, targetHandleName: logic.input.name },
    // );

    dispatch(setQuerybuilderGraphology(graphologyGraph));
    props.onClick(value);
  };

  return (
    <div className={props.className + ' card'}>
      {props.title && <h1 className="card-title mb-7">{props.title}</h1>}
      <div className="gap-1 flex">
        <TooltipProvider delayDuration={50}>
          {dataOps.map((item, index) => (
            <Tooltip key={item.title}>
              <TooltipContent>{item.description}</TooltipContent>
              <TooltipTrigger>
                <Button
                  iconComponent={item.icon}
                  size="sm"
                  variant={selectedOp === index ? 'solid' : 'outline'}
                  onClick={(e) => {
                    e.preventDefault();
                    index === selectedOp ? setSelectedOp(-1) : setSelectedOp(index);
                  }}
                ></Button>
              </TooltipTrigger>
            </Tooltip>
          ))}
        </TooltipProvider>
        <div className="w-2" />
        {dataTypes.map((item, index) => (
          <div key={item.title} data-tip={item.description} className="tooltip tooltip-top m-0 p-0">
            <Button
              iconComponent={item.icon}
              size="sm"
              variant={selectedType === index ? 'solid' : 'outline'}
              onClick={(e) => {
                e.preventDefault();
                index === selectedType ? setSelectedType(-1) : setSelectedType(index);
              }}
            ></Button>
          </div>
        ))}
      </div>
      <div className="overflow-x-hidden h-[75rem] w-full mt-1">
        <ul className="menu p-0 [&_li>*]:rounded-none w-full pb-10 h-full gap-1">
          {Object.values(AllLogicMap)
            .filter((item) => !filterType || item.key.toLowerCase().includes(filterType))
            .filter((item) => selectedOp === -1 || item.key.toLowerCase().includes(dataOps?.[selectedOp].title))
            .filter((item) => selectedType === -1 || item.key.toLowerCase().includes(dataTypes?.[selectedType].title))
            .map((item, index) => (
              <li key={item.key + item.description} className="h-fit bg-white border-[1px] border-secondary-500 rounded-sm">
                <span
                  data-tip={item.description}
                  className="flex before:w-[10rem] before:text-center tooltip tooltip-bottom text-start "
                  onDragStart={(e) => onDragStart(e, item)}
                  draggable={true}
                  onClick={() => {
                    if (props.editNode) onEditNodeFromPopup(item);
                    else onNewNodeFromPopup(item);
                  }}
                >
                  {item.icon && (
                    <div className="w-[1rem] rounded-sm justify-center flex">
                      <span>{item.icon}</span>
                    </div>
                  )}
                  <span className="w-full">{item.name}</span>
                  <span className="flex scale-75">
                    {item.key.toLowerCase().includes('filter') && <FilterAltIcon fontSize="small" />}
                    {item.key.toLowerCase().includes('function') && <FunctionsIcon fontSize="small" />}
                    {item.key.toLowerCase().includes('aggregation') && <GridOnIcon fontSize="small" />}
                    {item.key.toLowerCase().includes('number') && <NumbersIcon fontSize="small" />}
                    {item.key.toLowerCase().includes('string') && <AbcIcon fontSize="small" />}
                  </span>
                </span>
              </li>
            ))}
        </ul>
      </div>
    </div>
  );
};