import { PropBindType } from '@cloudbase/cals';
import { observable, reaction, remove, untracked } from 'mobx';
import { EventProxy } from './eventProxy';
import { generateDataBinds } from './adapter/generate';

/**
 * 以 widget id 为 key，只记录同个 widget 的最后一次表达式的结果
 * 这里因为同时只会执行（调试）一个表达式，所以只需保存最后一次执行的结果即可
 */

const eventProxy = new EventProxy();

export let debugExprMap = observable<{
  node: {
    [nodeId: string]: {
      expr: string;
      result: any;
      refreshSigh: number;
    };
  };
}>({ node: {} });

export function resetDebugExprMap() {
  // FIXME: widgets 中 for 之下 widget 的 dispose 没有被触发，所以这边通过 remove 来删除使原来的 autorun 不再触发
  remove(debugExprMap, 'node');
  debugExprMap.node = {};
  // window['__debugExprMap'] = debugExprMap
}

export function watchForDebugExpr({ widgetId, subForItems, globalCtx, getDataContextFn, get$wFn, get$scopeFn }) {
  // FIXME: 暂时没考虑低码组件开发模式
  const dataContext = untracked(getDataContextFn);
  const $w = untracked(get$wFn);
  const $scope = untracked(get$scopeFn);

  if (!debugExprMap.node[widgetId]) {
    debugExprMap.node[widgetId] = {
      expr: '',
      result: '',
      refreshSigh: +new Date(),
    };
  }

  const forDebugExprDispose = reaction(
    // 监听 refreshSigh 的变化
    () => [debugExprMap.node[widgetId]?.refreshSigh, debugExprMap.node[widgetId]?.expr],
    ([_, expr]: [number, string]) => {
      if (expr?.trim()) {
        const fn = generateDataBinds(globalCtx, [
          {
            type: PropBindType.expression,
            bindDataPath: expr,
            propertyPath: 'expr',
          },
        ])?.expr;
        if (fn) {
          try {
            const result = fn(subForItems, undefined, dataContext, $w, $scope);
            debugExprMap.node[widgetId].result = result;
          } catch (e) {
            debugExprMap.node[widgetId].result = e;
          }
        } else {
          debugExprMap.node[widgetId].result = '';
        }
      } else {
        if (debugExprMap.node?.[widgetId]) debugExprMap.node[widgetId].result = '';
      }

      eventProxy.emit(`done_${widgetId}_${expr}`);
    },
  );

  return forDebugExprDispose;
}

export function evalExpr(widgetId: string, expr: string, useCache = false) {
  return new Promise((resolve) => {
    if (!debugExprMap.node[widgetId]) {
      resolve(undefined);
      return;
    }

    if (useCache && debugExprMap.node[widgetId].expr === expr) {
      // 表达式没变，直接返回结果
      resolve(debugExprMap.node[widgetId].result);
    } else {
      eventProxy.once(`done_${widgetId}_${expr}`, () => {
        resolve(debugExprMap.node[widgetId].result);
      });

      // 触发 autorun
      if (!useCache && debugExprMap.node[widgetId].expr === expr) {
        debugExprMap.node[widgetId].refreshSigh = +new Date();
      } else {
        debugExprMap.node[widgetId].expr = expr || '';
      }
    }
  });
}

// window['__testExpr'] = evalExpr
