import React, { useCallback } from 'react';
import { useRecoilState } from 'recoil';
import {
  ComponentTypeEnum,
  UpdateComponentQuery,
  StateTypeEnum,
  UpdateViewpointQuery,
  ComponentInfo,
  StateInfo,
  ViewpointInfo,
  UpdateStateQuery,
  ComponentDetailInfo,
} from '@easytwin/core';
import {
  _currentComponentDetail,
  _componentStateList,
  _componentStateSelectKey,
  _componenterAnimationList,
  _componenterAnimationSelectKey,
  _componenterViewpointList,
  _componenterViewpointSelectKey,
  _currentScene,
  useComponenterState,
  useComponenterViewpoint,
} from '@/pages/ProjectEditor/module';
import { ComponentApi, initStateData } from '@/server';
import { UpdateObjConfigDto } from '@/types/api.swagger-schema-types';
import BizGroupConfig from './BizGroupConfig';
import BaseComponenterConfig from './BaseComponenterConfig';
import TeamplateGroupConfig from './TeamplateGroupConfig';
import TeamplateComponenterConfig from './TeamplateComponenterConfig';
import BatchModelConfig from './BatchModelConfig';
import BatchModelLineConfig from './BatchModelLineConfig';

type Component = ComponentDetailInfo & ComponentInfo; // FIXME:

export interface ComponenterDetailsProp {
  onBaseFormValuesChange?: (values: UpdateObjConfigDto) => void;
}
export default function ComponenterConfigForm({ onBaseFormValuesChange }: ComponenterDetailsProp) {
  const [_componentDetail, setComponentDetail] = useRecoilState(_currentComponentDetail);
  const componentDetail = { ..._componentDetail, children: [] } as Component; // FIXME:

  const [currentScene] = useRecoilState(_currentScene);

  /**
   * state
   */
  const [stateList] = useRecoilState(_componentStateList);
  const [stateSelectKey, setStateSelectKey] = useRecoilState(_componentStateSelectKey);

  const handleCreateState = useCallback(async () => {
    if (componentDetail) {
      const newState = await ComponentApi.addState({
        rank: 0,
        objId: componentDetail.id,
        config: initStateData[StateTypeEnum[componentDetail.type]],
      });

      const newStateDetail = await ComponentApi.getState({
        objId: componentDetail.id,
        stateId: newState.stateId,
      });

      const config = newStateDetail.config as StateInfo;
      setComponentDetail((prev) => {
        if (!prev) return;
        return {
          ...prev,
          stateConfig: [...prev?.stateConfig, config],
        };
      });

      setStateSelectKey(newState.stateId);
    }
  }, [componentDetail]);

  const handleDeleteState = useCallback(
    async (id: string) => {
      if (componentDetail) {
        await ComponentApi.deleteState({
          objId: componentDetail.id,
          stateId: id,
        });

        setComponentDetail((prev) => {
          if (!prev) return;
          return {
            ...prev,
            stateConfig: prev?.stateConfig.filter((d) => d.id !== id),
          };
        });

        const latestStateConfig = componentDetail.stateConfig.filter((d) => d.id !== id);
        if (latestStateConfig.length > 0) {
          setStateSelectKey(latestStateConfig[0].id);
        }
      }
    },
    [componentDetail],
  );

  const handleUpdateState = useCallback(
    async ({ id, config }: Partial<UpdateStateQuery>) => {
      if (componentDetail && id && config) {
        await ComponentApi.updateState({
          objId: componentDetail.id,
          stateId: id,
          config,
        });
        setComponentDetail((prev) => {
          if (!prev) return;
          return {
            ...prev,
            stateConfig: prev?.stateConfig.map((d) => (d.id === id ? { ...d, config } : d)),
          };
        });
      }
    },
    [componentDetail],
  );

  /**
   * animation
   */

  const [animationList] = useRecoilState(_componenterAnimationList);
  const [animationSelectKey, setAnimationSelectKey] = useRecoilState(
    _componenterAnimationSelectKey,
  );

  /**
   * viewpoint
   */
  const [viewpointList] = useRecoilState(_componenterViewpointList);
  const [viewpointSelectKey, setViewpointSelectKey] = useRecoilState(
    _componenterViewpointSelectKey,
  );

  const handleCreateViewpoint = useCallback(async () => {
    if (componentDetail && currentScene) {
      try {
        const newViewpoint = await ComponentApi.addViewpoint({
          objId: componentDetail.id,
          config: currentScene.getCameraState(),
        });

        const newViewpointDetail = await ComponentApi.getViewpoint({
          objId: componentDetail.id,
          viewpointId: newViewpoint.viewpointId,
        });

        const config = newViewpointDetail.config as ViewpointInfo;

        // TODO: 更新componenterList
        setComponentDetail((prev) => {
          if (!prev) return;
          return {
            ...prev,
            viewpointConfig: [...prev.viewpointConfig, config],
          };
        });
        setViewpointSelectKey(config.id);
      } catch (error) {
        console.error(error);
      }
    }
  }, [componentDetail, currentScene]);

  const handleUpdateViewpoint = useCallback(
    async (viewpoint: Partial<UpdateViewpointQuery>) => {
      if (componentDetail && currentScene && viewpoint.id) {
        try {
          await ComponentApi.updateViewpoint({
            objId: componentDetail.id,
            id: viewpoint.id,
            name: viewpoint.name,
            config: currentScene.getCameraState(),
          });

          const newViewpointDetail = await ComponentApi.getViewpoint({
            objId: componentDetail.id,
            viewpointId: viewpoint.id,
          });

          const config = newViewpointDetail.config as ViewpointInfo;

          setComponentDetail((prev) => {
            if (!prev) return;
            return {
              ...prev,
              viewpointConfig: prev?.viewpointConfig.map((d) =>
                d.id === viewpoint.id ? config : d,
              ),
            };
          });
        } catch (error) {
          console.error(error);
        }
      }
    },
    [componentDetail, currentScene],
  );

  const handleDeleteViewpoint = useCallback(
    async (id: string) => {
      if (componentDetail && currentScene) {
        await ComponentApi.deleteViewpoint({
          objId: componentDetail.id,
          viewpointId: id,
        });

        setComponentDetail(
          (prev) =>
            ({
              ...prev,
              viewpointConfig: prev?.viewpointConfig.filter((d) => d.id !== id),
            } as ComponentDetailInfo),
        );

        const latestViewpointConfig = componentDetail.viewpointConfig.filter((d) => d.id !== id);
        if (latestViewpointConfig.length > 0) {
          setViewpointSelectKey(latestViewpointConfig[0].id);
        }
      }
    },
    [componentDetail, currentScene],
  );

  const handleUpdateAnimation = () => {};

  const renderComponent = () => {
    if (componentDetail) {
      if (componentDetail.commonConfig?.isGroup) {
        if (componentDetail.type === ComponentTypeEnum.BIZGROUP) {
          return (
            <BizGroupConfig
              component={componentDetail}
              viewpointList={viewpointList}
              viewpointSelectKey={viewpointSelectKey}
              onBaseFormValuesChange={onBaseFormValuesChange}
              onViewpointTabChange={setViewpointSelectKey}
              onViewpointFlyTo={() => {
                const old = viewpointSelectKey;
                setViewpointSelectKey(undefined);
                setTimeout(() => setViewpointSelectKey(old), 0);
              }}
              onAddViewpoint={handleCreateViewpoint}
              onUpdateViewpoint={handleUpdateViewpoint}
              onRemoveViewpoint={handleDeleteViewpoint}
            />
          );
        } if (componentDetail.type === ComponentTypeEnum.BATCH) {
          return (
            <BatchModelConfig
              component={componentDetail}
              onFormValuesChange={onBaseFormValuesChange}
            />
          );
        }
      }
      if (
        componentDetail.type === ComponentTypeEnum.MODEL ||
        componentDetail.type === ComponentTypeEnum.POINTLIGHT ||
        componentDetail.type === ComponentTypeEnum.DIRECTLIGHT
      ) {
        return (
          <BaseComponenterConfig
            component={componentDetail}
            stateSelectKey={stateSelectKey}
            animationList={animationList}
            animationSelectKey={animationSelectKey}
            viewpointSelectKey={viewpointSelectKey}
            onBaseFormValuesChange={onBaseFormValuesChange}
            onStateTabChange={setStateSelectKey}
            onAddState={handleCreateState}
            onUpdateState={handleUpdateState}
            onRemoveState={handleDeleteState}
            onAnimationTabChange={setAnimationSelectKey}
            onUpdateAnimation={handleUpdateAnimation}
            onViewpointTabChange={setViewpointSelectKey}
            onViewpointFlyTo={() => {
              const old = viewpointSelectKey;
              setViewpointSelectKey(undefined);
              setTimeout(() => setViewpointSelectKey(old), 0);
            }}
            onAddViewpoint={handleCreateViewpoint}
            onUpdateViewpoint={handleUpdateViewpoint}
            onRemoveViewpoint={handleDeleteViewpoint}
          />
        );
      } if (componentDetail.type === ComponentTypeEnum.LINE) {
        return <BatchModelLineConfig component={componentDetail} />;
      }
      // return (
      //   <TeamplateComponenterConfig
      //     componentDetail={componentDetail}
      //     stateList={stateList}
      //     stateSelectKey={stateSelectKey}
      //     onBaseFormValuesChange={onBaseFormValuesChange}
      //     onStateTabChange={setStateSelectKey}
      //     onUpdateState={updateState}
      //   />
      // );
    }
    return null;
  };

  return <div className="w-full h-full">{renderComponent()}</div>;
}
