import React from 'react';
import { useRecoilState } from 'recoil';
import {
  FolderFilled,
  ModelOutlined,
  EyeOutlined,
  EyeInvisibleOutlined,
  LockOutlined,
  UnlockOutlined,
  SpotLightOutlined,
  DirectionalLightOutlined,
  AdditionalLayersOutlined,
  BatchModelOutlined,
  BatchModelLinesOutlined,
} from '@easyv/react-icons';
import {
  ComponentTypeEnum,
  ComponentInfo,
  ComponentDetailInfo,
  treeList2SimpleList,
} from '@easytwin/core';
import classnames from 'classnames';
import {
  DraggableTree,
  DraggableTreeRenderNodeState,
  DraggableTreeDropEventInfo,
} from '@/components';
import { ComponentApi } from '@/server';
import {
  _componenterTreeList,
  _componentSelectList,
  _sceneId,
  _componenterSearchQuery,
} from '@/pages/ProjectEditor/module';
import { TreeDraggableType } from './enum';
import { deepFilter } from '../../../../utils';

export interface LeftTreeProp {
  editingKey?: string;
  onSelect?: (infos: ComponentInfo[]) => void;
  onVisibleClick?: (id: string, visible: boolean) => void;
  onInActiveClick?: (id: string, inActive: boolean) => void;
  onRightClick?: (style: React.CSSProperties) => void;
  onNameEditChange?: (id: string, name: string) => void;
  onExpandChange?: (id: string, collapsed: boolean) => void;
  onDrop?: (id: string, parentObjId: string | null, rank: number) => void;
}

export default function ComponenterTree({
  editingKey,
  onSelect,
  onVisibleClick,
  onInActiveClick,
  onRightClick,
  onNameEditChange,
  onExpandChange,
  onDrop,
}: LeftTreeProp) {
  const [componenterTreeList] = useRecoilState(_componenterTreeList);
  const [searchQuery] = useRecoilState(_componenterSearchQuery);
  const [sceneId] = useRecoilState(_sceneId);

  const treeData = React.useMemo(() => {
    if (!componenterTreeList) {
      return [];
    }

    let componenters = componenterTreeList;
    if (searchQuery?.name) {
      componenters = deepFilter(
        componenters,
        (item) => item.name.includes(searchQuery.name),
        'children',
      );
    }
    return treeList2SimpleList(componenters);
  }, [componenterTreeList, searchQuery]);

  const [selectComponents, setSelectComponents] = useRecoilState(_componentSelectList);

  const handleDragStart = React.useCallback(
    async (_: any, { id }: ComponentInfo) => {
      if (!sceneId) return;
      const compoenter = await ComponentApi.getDetail({
        sceneId,
        id,
      });
      if (!compoenter) return;
    },
    [sceneId],
  );

  const handleRightClick = (event: React.MouseEvent<HTMLElement>, node: ComponentInfo) => {
    event.preventDefault();
    const index = selectComponents.findIndex((item) => item.id === node.id);
    if (index === -1) {
      setSelectComponents([node]);
      onSelect?.([node]);
    }

    onRightClick?.({
      top: event.clientY - 10,
      left: event.clientX + 1,
    });
  };

  const handleDrop = ({ source, target, targetNext }: DraggableTreeDropEventInfo) => {
    const { id } = source;
    const parentObjId = target.isGroup ? target.id : target.parentObjId;
    const rank = targetNext ? (targetNext.rank + target.rank) / 2 : target.rank + 1;

    onDrop?.(id, parentObjId, rank);
  };

  const iconRender = (type: ComponentTypeEnum) => {
    switch (type) {
      case ComponentTypeEnum.BIZGROUP:
        return <FolderFilled className="anticon" />;
      case ComponentTypeEnum.MODEL:
        return <ModelOutlined className="anticon" />;
      case ComponentTypeEnum.POINTLIGHT:
        return <SpotLightOutlined className="anticon" />;
      case ComponentTypeEnum.DIRECTLIGHT:
        return <DirectionalLightOutlined className="anticon" />;
      case ComponentTypeEnum.BATCH:
        return <BatchModelOutlined className="anticon" />;
      case ComponentTypeEnum.LINE:
        return <BatchModelLinesOutlined className="anticon" />;
      default:
        return <AdditionalLayersOutlined className="anticon" />;
    }
  };

  const extendRender = (node: ComponentInfo, { isSelected }: DraggableTreeRenderNodeState) =>
    (!node.commonConfig.isGroup || node.type !== ComponentTypeEnum.BIZGROUP) && (
      <span className="flex gap-x-1 cursor-pointer">
        <span
          onClick={(e) => {
            e.stopPropagation();
            setSelectComponents([node]);
            onSelect?.([node]);

            onInActiveClick?.(node.id, !node.commonConfig.inActive);
          }}>
          {node.commonConfig.inActive ? (
            <LockOutlined
              className={classnames('anticon', isSelected ? '!text-white' : '!text-primary')}
            />
          ) : (
            <UnlockOutlined className={classnames('anticon', isSelected ? '!text-white' : '')} />
          )}
        </span>
        <span
          onClick={(e) => {
            e.stopPropagation();
            setSelectComponents([node]);
            onSelect?.([node]);

            onVisibleClick?.(node.id, !node.visible);
          }}>
          {node.visible ? (
            <EyeOutlined className={classnames('anticon', isSelected ? '!text-white' : '')} />
          ) : (
            <EyeInvisibleOutlined
              className={classnames('anticon', isSelected ? '!text-white' : '!text-primary')}
            />
          )}
        </span>
      </span>
    );

  return (
    <div
      className="h-full"
      onClick={() => {
        setSelectComponents([]);
        onSelect?.([]);
      }}>
      <DraggableTree
        dataSource={treeData}
        selectedKeys={selectComponents.map((item) => item?.id)}
        editingKey={editingKey}
        dragType={TreeDraggableType.scene}
        allowVisible={(node: ComponentInfo) => {
          const { parentObjId, commonConfig, type } = node;
          const parent = treeData.find((item) => item.id === parentObjId);

          // return !!(parent ? parent.commonConfig?.collapsed : true);
          return true;
        }}
        iconRender={(node: ComponentInfo) => iconRender(ComponentTypeEnum[node.type])}
        extendRender={extendRender}
        onSelect={(_, infos: ComponentInfo[]) => {
          setSelectComponents(infos);
          onSelect?.(infos);
        }}
        onRightClick={handleRightClick}
        onDragStart={handleDragStart}
        onNameEditChange={onNameEditChange}
        onExpandChange={(_, node: ComponentInfo) =>
          onExpandChange?.(node.id, !node.commonConfig.collapsed)
        }
        onDrop={handleDrop}
      />
    </div>
  );
}
