import { resolveDataBinds } from '../common';
import { set as lodashSet } from 'lodash-es';
import { app } from '../../app/global-api';

const DEFAULT_MAX_TIMEOUT = 10 * 1000;

export function emitEvent(trigger, listeners = [], args, scopeContext = {}, dataContext) {
  const targetListeners = listeners.filter((l) => l.trigger === trigger);

  async function processListener(listener) {
    // 当前非捕获Event，再判断冒泡行为
    if (!args?.event?.isCapturePhase && listener.noPropagation) {
      args?.domEvent?.stopPropagation && args?.domEvent?.stopPropagation();
    }

    // 判断捕获的执行，只有执行的捕获与配置的捕获一致时。才会执行。
    if ((listener?.isCapturePhase || false) === (args?.customEventData?.isCapturePhase || false)) {
      try {
        const res = await invokeListener(listener, args, scopeContext, dataContext);
        const eventName = `${listener.key}.success`;
        const event = {
          detail: res,
          isCapturePhase: !!args.event?.isCapturePhase,
          origin: args.event,
          name: eventName,
        };
        emitEvent(
          eventName,
          listeners,
          {
            ...args,
            event,
            customEventData: event,
          },
          scopeContext,
          dataContext,
        );
        // if (res) {
        //   console.warn(
        //     `@deprecated 事件编排中后续事件(${eventName}) event.detail.value.xxx 已废弃，建议使用 event.detail 直接访问前一动作返回值`,
        //   );
        // }
      } catch (e) {
        const eventName = `${listener.key}.fail`;

        if (e.message) {
          e.message = `[${listener.trigger}] ${e.message}`;
        }

        const event = {
          detail: e,
          origin: args.event,
          isCapturePhase: !!args.event?.isCapturePhase,
          name: eventName,
        };
        emitEvent(
          eventName,
          listeners,
          {
            ...args,
            event,
            customEventData: event,
          },
          scopeContext,
          dataContext,
        );
        // 之前 invoke 内部catch 了错误，不会抛错
        // throw e
        console.error(`Action error: [${listener.trigger}]`, e);
      }
    }
  }

  if (!targetListeners.length && typeof trigger === 'string' && /\.fail$/.test(trigger)) {
    app.showToast({
      title: `事件响应失败：${args.event.detail}`,
      icon: 'error',
    });
  } else {
    targetListeners.forEach((listener) => {
      processListener(listener);
    });
  }
}

function invokeListener({ instanceFunction, data = {}, dataBinds = {} }, args, scopeContext, dataContext) {
  // ToDo resolve databinds
  const action = instanceFunction;
  const resolvedData = {
    ...data,
  };
  const resolvedDataBinds = resolveDataBinds(
    dataBinds,
    args.forItems,
    { event: args.event },
    scopeContext,
    true,
    dataContext,
  );

  // eslint-disable-next-line no-restricted-syntax
  for (const key in resolvedDataBinds) {
    if (resolvedDataBinds[key] && resolvedDataBinds[key].__type === 'scopedValue') {
      try {
        lodashSet(resolvedData, key, resolvedDataBinds[key].getValue(scopeContext));
      } catch (e) {
        lodashSet(resolvedData, key, '');
      }
    } else {
      lodashSet(resolvedData, key, resolvedDataBinds[key]);
    }
  }
  const params = {
    data: resolvedData,
    ...args,
  };

  return action(params);
}
