import { actionTypes } from 'constants/action-types';
import { getInteractions, getId } from 'utils/interaction';
import { api } from '../constants/config';
import http from '../utils/fetch';
import message from 'components/message';
import { Utils } from '@easyv/react-gui';
import defaultActions from 'constants/default-actions';
import { filterData, mappingData } from 'utils/convert';

const { updateArrayWithObject } = Utils;

function getActionData(fn: string, data: any) {
  let result: any;
  try {
    result = eval(`(function emitData(data){
      ${fn}
    })(data)`);
  } catch (error) {
    console.error(error);
  }

  return result;
}

export function emitEvent(payload) {
  return (dispatch, getState) => {
    const {
      type,
      component,
      state = {},
      activeState = {},
      controllers,
      componentConfig,
      action,
    } = payload;

    if (!component) {
      return;
    }

    const componentId: any = getId(component);
    if (action && !defaultActions.some((o) => o.value === action)) {
      const { componentsById, callback, filters } = getState();
      // 自定义动作
      const { actionData, actionDataFn, triggerComponentId } = payload;
      const event: any = new Event(`${action}_${componentId}`);
      if (actionDataFn) {
        try {
          const {
            dataType,
            dataConfigs,
            useFilter,
            filters: componentFilters = [],
          } = componentsById[getId(triggerComponentId)] || {};
          const { data, fields = [] } = dataConfigs[dataType];
          let componentData = data;

          if (useFilter) {
            componentData = filterData({
              data,
              filters: componentFilters
                .filter((d) => d.enable)
                .map((d) => filters.find((o) => o.id === d.id))
                .filter((d) => d),
              callbackValues: callback.callbackValues,
              id: componentId,
              name: componentsById[componentId]?.name,
            });
            if (!componentData || componentData.isError) {
              componentData = [];
            }
          }
          componentData = mappingData(componentData, fields);
          event.dynamicData = getActionData(actionDataFn, componentData);
        } catch (error) {
          console.log(error);
        }
      }

      event.data = actionData;

      document.dispatchEvent(event);
      return;
    }

    if (type === 'updateConfig' || action === 'updateConfig') {
      // 兼容动作字段 远程控制用的是action 平台用的是type
      const { backup } = getState();
      const { componentsById } = backup;
      const component = componentsById[componentId];

      if (component) {
        dispatch({
          type: actionTypes.COMPONENT_UPDATE,
          payload: {
            id: componentId,
            config: updateArrayWithObject(component.config, componentConfig),
          },
        });
      }

      return;
    }

    if (state.stateId) {
      state.stateId = getId(state.stateId);
    }

    dispatch({
      type: actionTypes.EVENT_EMIT,
      payload: {
        component: componentId,
        state,
        activeState,
        controllers,
      },
    });
  };
}

export function switchPanelState(id) {
  return (dispatch, getState) => {
    const { panelsById, interactions } = getState();
    const panelId: any = getId(id);
    const { states = [], config = {} } = panelsById[panelId];

    const { animateType } = config;
    if (states.length > 1) {
      const panelState = interactions.find((d) => d.id === id);
      if (panelState && panelState.state.show) {
        const current = panelState.state.stateId;
        let currentIndex = states.findIndex((d) => d === current);
        currentIndex = currentIndex === -1 ? 0 : currentIndex;
        const nextStateId = states[(currentIndex + 1) % states.length];

        dispatch({
          type: actionTypes.EVENT_EMIT,
          payload: {
            component: id,
            state: {
              show: true,
              stateId: nextStateId,
              unmount: false,
            },
            activeState: {
              animation: {
                key: 'show',
                from: {
                  opacity: 0,
                },
                to: {
                  opacity: 1,
                },
                config: {
                  duration: animateType === 'none' ? 0 : 600,
                  timingFunction: 'ease',
                  delay: 0,
                },
              },
            },
          },
        });
      }
    }
  };
}

export async function login({ id, password }) {
  let error = false;
  await http.get(
    api.interactionCheckPassword,
    { id, controlCode: password },
    {
      error: (res) => {
        message.error(res.message);
        error = true;
      },
    },
  );
  return error ? Promise.reject() : null;
}

const initialState = [];

export default function reducer(state = initialState, { type, payload }) {
  switch (type) {
    case actionTypes.EVENTS_INIT: {
      const { components, layers } = payload;
      const interactions = getInteractions(components, layers);
      const result = interactions.reduce((all, item) => {
        const exist = all.find((o) => o.id === item.id);

        if (exist) {
          exist.state = exist.state.show === false ? { ...item.state, show: false } : item.state;
          exist.controllers = exist.controllers.concat(item.controllers);
          return all;
        } else {
          return all.concat(item);
        }
      }, state);
      return result;
    }

    case actionTypes.EVENT_EMIT: {
      const { component } = payload;
      if (!component) {
        return state;
      }

      if (!payload.state) {
        payload.state = {};
      }

      if (!payload.activeState) {
        payload.activeState = {};
      }

      const eventState = state.find((d: any) => d.id === component);
      const { unmount = false } = payload.state; // 是否卸载，默认false 未卸载

      return eventState
        ? state.reduce((result: any, current: any) => {
            if (current.id == component) {
              payload.state = Object.keys(payload.state).reduce((obj, key) => {
                if (payload.state[key] === '$not') {
                  obj[key] = !current.state[key];
                } else {
                  obj[key] = payload.state[key];
                }

                return obj;
              }, {});

              return result.concat([
                {
                  ...current,
                  state: {
                    ...current.state,
                    ...payload.state,
                  },
                  activeState: {
                    ...current.activeState,
                    ...payload.activeState,
                  },
                },
              ]);
            } else {
              return result.concat([current]);
            }
          }, [])
        : payload.state.show === '$not'
        ? state.concat({ ...payload, state: { show: false, unmount }, id: component })
        : state.concat({ ...payload, id: component });
    }

    default:
      return state;
  }
}
