import sdk from '@tcwd/weapps-sdk/lib/app-h5-sdk';

import {
  createWebApp,
  _ACTIONS_KEY as ACTIONS_KEY,
  _ROUTER_KEY as ROUTER_KEY,
  _WEDA_CLOUD_SDK as WEDA_CLOUD_SDK,
} from '@cloudbase/weda-client';
import { runtime } from '../utils/adapter/index';
import { getEnumOptions } from '../utils/initGlobalVar';
import { get as lodashGet } from 'lodash-es';

export const OFFICIAL_LIB_KEY = 'gsd-h5-react';
interface IBaseState {
  state: {
    [key: string]: any;
  };
  computed: {
    [key: string]: any;
  };
  dataset?: {
    state?: {};
  };
}

enum EPLATFORM {
  WEB = 'WEB',
  /**
   * 拼写错误
   * 兼容性无法修改
   */
  MINIPROGRAM = 'MINIPROGRAME',
}

const DEFAULT_INIT_DATA = {
  processAction: (key, action) => {
    switch (key) {
      case ACTIONS_KEY.showModal: {
        return function (obj) {
          const showModal = runtime[`@weapps-materials-main-${OFFICIAL_LIB_KEY}`]?.actions?.showModal;
          const isMobile = (app?.__internal__ as any)?.isMobile;
          if (isMobile && !isMobile() && showModal) {
            return showModal({ data: obj });
          }
          return action(obj);
        };
      }
    }
    return action;
  },
};

export const subPackageName = '';
export let app = createGlboalApi(DEFAULT_INIT_DATA);
export function registerApp(_app = createGlboalApi(DEFAULT_INIT_DATA)) {
  _injectApp2Runtime(_app, true);
  app = _app;
}

mountAPIs(sdk);
export interface IAppAPI extends IBaseState {
  id: string;
  platform: EPLATFORM;
  __internal__?: {
    getConfig: Function;
  };
  app?: IAppAPI;
  $app?: IAppAPI;
  mainApp?: IAppAPI;
  common: {};
  enumOptions?: {};
  domain: string;
  cloud: typeof WEDA_CLOUD_SDK.CLOUD_SDK;
  /**
   * @deprecated
   */
  dataSources: any;
  utils: {
    formatDate: Function;
    formatEnum: Function;
    get: Function;
    set: Function;
    getCurrentPage: Function;
  };
  /**
   * 内置方法
   */
  _setStateVal: ({ varPath, val }) => void;
  setState: (state) => void;
  /**
   * 微信继承方法
   */
  showLoading?: (param?) => void;
  hideLoading?: () => void;
  showToast?: (param) => void;
  redirectTo?: (param) => void;
}

function createGlboalApi(
  initData: {
    id?: string;
    domain?: string;
    appConfig?: {
      id?: string;
      envId?: string;
      envVersion?: 'preview' | 'production';
      staticResourceDomain?: string;
      pages: { id: string }[];
    };
    processAction?: (key, action) => any;
  } = {},
): IAppAPI {
  const webApp = createWebApp(initData);
  const globalAPI: IAppAPI = new Proxy(
    {
      id: initData.id || '',
      domain: initData.domain || '',
      state: {},
      computed: {},
      dataset: {},
      common: {},
      enumOptions: {},
      // i18n,
      ...webApp,
      utils: {
        ...webApp.utils,
        formatEnum: (path, optionname, app) => {
          let isSingle = Array.isArray(path);
          // 这个app是后来添加进去的
          let options = app?.enumOptions;
          let parseOptions = options[optionname] ? options[optionname] : getEnumOptions(optionname);
          if (parseOptions === '') {
            return !isSingle ? path : path.join(',');
          }
          let multiTmp = [];
          let value = !isSingle
            ? JSON.parse(parseOptions)?.find((item) => item.key === path)?.value
            : JSON.parse(parseOptions)
                ?.filter((item) => path.some((pathValue) => item.key === pathValue))
                .map((item) => multiTmp.push(item.value));
          return !isSingle ? value : multiTmp.join(',');
        },
      },
      /**
       * setState
       */
      setState: (userSetState) => {
        Object.keys(userSetState).forEach((keyPath) => {
          globalAPI.utils.set(globalAPI.dataset.state, keyPath, userSetState[keyPath]);
        });
      },
      invoke(params) {
        const $page = globalAPI.utils.getCurrentPage();
        return $page.invokeComponentMethod(params);
      },
    },
    {
      get: (obj, prop) => {
        if (prop === 'app' || prop === '$app') {
          return app;
        } else {
          return obj[prop];
        }
      },
      // set: (obj, prop, value) => {
      //   if (prop === 'app' || prop === '$app') {
      //     console.warn('$app 对象中 app/$app 为只读');
      //     return false;
      //   } else {
      //     // 修改 obj
      //     return true;
      //   }
      // },
    },
  );
  _injectApp2Runtime(globalAPI);

  return globalAPI;
}

function _injectApp2Runtime(globalAPI, hard = false) {
  // 给全局挂上 mainApp/subApp
  // The global api exposed to lowcode
  if (subPackageName) {
    globalAPI.mainApp = runtime[`$app`];
    (runtime as any)[`$$subapp_${subPackageName}`] = globalAPI;
  } else {
    // 预览区调试栏可调试
    // 暴露给复合组件，代码组件来引用
    runtime['app'] = hard ? globalAPI : runtime['app'] || globalAPI;
    runtime[`$app`] = new Proxy(runtime['app'], {
      get: function (obj, prop) {
        return runtime['app'] ? runtime['app'][prop] : undefined;
      },
      set: function (obj, prop, value) {
        if (runtime['app']) {
          return (runtime['app'][prop] = value);
        } else {
          return undefined;
        }
      },
    });
  }
}

export function removeGlboalApi() {
  if (subPackageName) {
    (runtime as any)[`$$subapp_${subPackageName}`] = undefined;
  } else {
    runtime['app'] = undefined;
    runtime[`$app`] = undefined;
  }
}

export interface IPageAPI extends IBaseState {
  $page?: IPageAPI;
  id?: string;
  handler: {
    [key: string]: any;
  };
  props: {
    [key: string]: any;
  };
  widgets: {
    [key: string]: any;
  };
  setState: (state) => void;
  _dataBinds: {
    [key: string]: any;
  };
}

export function createPageApi(): IPageAPI {
  const $page: IPageAPI = new Proxy(
    {
      state: {},
      computed: {},
      handler: {},
      props: {},
      widgets: {},
      dataset: {},
      setState: (userSetState) => {
        Object.keys(userSetState).forEach((keyPath) => {
          app.utils.set($page.dataset?.state, keyPath, userSetState[keyPath]);
        });
      },
      _dataBinds: {},
      invokeComponentMethod({ component, method, params }) {
        const widgetData = lodashGet($page.widgets, component);
        if (Array.isArray(widgetData)) {
          throw new Error(`调用方法失败：id为${component}的组件拥有多个实例`);
          // widgetData.forEach(widget => {
          //   if(!widget._methods[method]) {
          //     throw new Error('NOT_FOUND')
          //   } else {
          //     actions.push(widget._methods[method])
          //   }
          // })
        } else {
          if (!widgetData._methods[method] || typeof widgetData._methods[method] != 'function') {
            throw new Error(`调用方法失败：未找到id为${component}下的方法${method}`);
          }
          return widgetData._methods[method](params);
        }
      },
    },
    {
      get(obj, prop) {
        return prop === '$page' ? obj : obj[prop];
      },
    },
  );
  return $page;
}

// 分app 和 wx 挂载app
function mountAPIs(sdks) {
  Object.keys(sdks).forEach((item) => {
    let action = sdks[item];
    if (!(item in ACTIONS_KEY) && !(item in ROUTER_KEY)) {
      app[item] = action;
    }
  });
  return app;
}
