import { observable } from 'mobx';
import { createComputed, createEventHandlers, checkAuth } from './util';
import { createWidgets, createInitData, disposeWidget, ID_SEPARATOR } from './widget';
import mergeRenderer from './merge-renderer';
import { createDataset, EXTRA_API, createStateDataSourceVar, generateParamsParser, setConfig } from '../datasources/index';
import { runWatchers } from './watch'
import lodashGet from 'lodash.get';
import { getMpEventHandlerName } from "./util";

export function createPage(
  id,
  uuid,
  widgetProps,
  index = {},
  lifecycle,
  pageState,
  pageComputed,
  evtListeners,
  dataBinds,
  app,
  handler,
  pageContext = {},
  pageAttributes
) {
  const evtHandlers = createEventHandlers(evtListeners);

  function extractLifecycles() {
    const result = {};
    Object.keys(lifecycle).map(name => {
      result[name] = function () {
        return lifecycle[name].apply(this.getWeAppInst(), arguments)
      }
    })

    result['onShareAppMessage'] = (res) => {
      if (res?.from === 'button' && res?.target?.dataset?.weda_share_info) {
        return res?.target?.dataset?.weda_share_info;
      }
      else if (res?.from === 'menu' && pageAttributes?.appShareMessage) {
        let { enable, pageId, params, imageUrl, title } = pageAttributes.appShareMessage;
        if (enable) {
          pageId = pageId ? pageId.replace(/^(\.)?\//, '') : pageId;
          let realPath = `/pages/${pageId}/index` + (params ? '?' + params.map(pair => pair.key + '=' + pair.value).join('&') : '');
          return {
            path: realPath,
            imageUrl,
            title
          };
        }
      }
      try {
        return lifecycle?.['onShareAppMessage']?.() || {};
      } catch (error) {
        console.log(error);
        return {};
      }
    }
    return result;
  }

  return Component({
    _componentType: 'page',
    data: createInitData(widgetProps, dataBinds),
    lifetimes: {
      attached() {
        const $page = this.getWeAppInst()
        this._pageActive = true;
        this.__mnt__ = (e) => {
          if (!$page.componentMethods) {
            $page.componentMethods = {};
          }
          const [id, index = 0] = e.target.id.split(ID_SEPARATOR);
          if (!$page.componentMethods[id]) {
            $page.componentMethods[id] = [];
          }
          $page.componentMethods[id][index] = e.detail.methods;
        };
        this.__unmnt__ = (e) => {
          const [id, index = 0] = e.target.id.split(ID_SEPARATOR);
          if ($page.componentMethods) {
            const components = $page.componentMethods[id];
            if (components) {
              components[index] = undefined;
              if (components.filter(com => com !== undefined).length === 0) {
                delete $page.componentMethods[id];
              }
            }
          }
        }
        this._disposers = this.initMergeRenderer($page.widgets);
      },
      detached() {
        const $page = this.getWeAppInst()
        this._pageActive = false
        disposeWidget($page._rootWidget)
        this._disposers.forEach(dispose => dispose())
      },
    },
    pageLifetimes: {
      // 组件所在页面的生命周期函数，定义下给运营平台上报用
      show: function () {
      },
      hide: function () {
      },
    },
    methods: {
      _pageActive: true,
      /** page lifecycles **/
      ...extractLifecycles(),
      ...evtHandlers,
      ...mergeRenderer,
      onLoad(options) {
        const $page = this.getWeAppInst()
        setConfig({ currentPageId: $page.uuid });
        app.__internal__.activePage = $page;
        this._pageActive = true;

        let query = decodePageQuery(options || {});
        EXTRA_API.setParams($page.uuid, query);
        createStateDataSourceVar($page.uuid, generateParamsParser({ app, $page }));

        const hook = lifecycle.onLoad || lifecycle.onPageLoad;
        hook && hook.call($page, query);

        this.invokeEventHandler(id, 'load', {detail: {query}});
      },
      onReady() {
        const $page = this.getWeAppInst();

        this._disposers.push(...runWatchers(index, this));

        const hook = lifecycle.onReady || lifecycle.onPageReady;
        hook && hook.call($page);

        this.invokeEventHandler(id, 'ready');
      },
      onUnload() {
        const $page = this.getWeAppInst()

        const hook = lifecycle.onUnload || lifecycle.onPageUnload;
        hook && hook.call($page);

        this.invokeEventHandler(id, 'unload');
      },
      async onShow() {
        const $page = this.getWeAppInst()
        setConfig({ currentPageId: $page.uuid });
        app.__internal__.activePage = $page;
        this._pageActive = true;

        const hook = lifecycle.onShow || lifecycle.onPageShow;
        hook && hook.call($page);

        // 权限检查
        if (await checkAuth(app, app.id, $page)) {
          this.setData({
            weDaHasLogin: true,
          });
        }

        this.invokeEventHandler(id, 'show');
      },
      onHide() {
        const $page = this.getWeAppInst()
        const hook = lifecycle.onHide || lifecycle.onPageHide;
        hook && hook.call($page);
        this._pageActive = false;

        // 触发页面节点事件
        this.invokeEventHandler(id, 'hide');
      },
      invokeEventHandler(id, triggerName, params = {}) {
        const keyName = getMpEventHandlerName(id, triggerName);
        typeof evtHandlers?.[keyName] === 'function' && evtHandlers[keyName].call(this, params);
      },
      getWeAppInst() {
        let $page = this.$WEAPPS_PAGE
        if ($page) { return $page }
        Object.assign(pageContext, {
          id,
          uuid,
          state: observable(pageState),
          widgets: {}
        })
        $page = pageContext;
        this.$WEAPPS_PAGE = $page
        $page.handler = Object.keys(handler).reduce((result, key) => {
          result[key] = handler[key].bind($page)
          return result
        }, {})
        $page.computed = createComputed(pageComputed, $page)
        let dataset = createDataset($page.uuid);
        $page.dataset = dataset;
        $page.state.dataset = dataset;
        $page.setState = (userSetState) => {
          Object.keys(userSetState).forEach((keyPath) => {
            app.utils.set($page.dataset.state, keyPath, userSetState[keyPath]);
          });
        };

        const { rootWidget } = createWidgets(widgetProps, dataBinds, $page.widgets, this)
        $page._rootWidget = rootWidget

        $page.invokeComponentMethod = ({ component, method, params }) => {
          const components = lodashGet($page.componentMethods, component);
          let componentInstance = undefined
          if (Array.isArray(components)) {
            if(components.length > 1){
              throw new Error('调用方法失败：id为'+component+'的组件拥有多个实例')
            }
            componentInstance = components[0]
            // components.forEach(component => {
            //   component[method](params);
            // })
          } else {
            componentInstance = components
          }

          if(!componentInstance?.[method] || typeof componentInstance[method]!= 'function') {
            throw new Error('调用方法失败：未找到id为'+component+'下的方法'+method)
          }
          return componentInstance[method](params);
        };

        return $page
      },
    },
  });
}

function decodePageQuery(query) {
  return Object.keys(query)
    .reduce((decoded, key) => {
      decoded[key] = decodeURIComponent(query[key]);
      return decoded;
    }, {});
}
