// 必须优先初始化数据源
import '<%= subLevelPath %>../datasources/index';
import { observable } from 'mobx'
import { createMpApp, generateDatasetQuery, watchAndSyncDatasetState2Local, createComputed, _lodashGet as lodashGet } from '@cloudbase/weda-client';

import appGlobal from '<%= subLevelPath %>../app/app-global'
import { default as cloudConfig } from '<%= subLevelPath %>../datasources/config'
import { createDataset } from '<%= subLevelPath %>../common/cloud-sdk'

import config from '<%= subLevelPath %>../common/config';

<%= importor.state? `import state from '../lowcode/state'` : "const state = {}" %>
<%= importor.computed? `import computed from '../lowcode/computed'` : "const computed = {}" %>
<%= importor.common? `import common from './common'` : "const common = {}" %>

const mainAppKey = '__weappsMainApp';
let GLOBAL_DATASET_SYNC_DISPOSES = [];


<% function printBoundData(boundData={}) {
  /**
   * TODO: copy 过来的代码
   * 一些模板层面的工具应该如何复用？
   */
  const list = []
  Object.entries(boundData).map(([prop, bindMeta])=>{
    const str = `'${prop}': ($app, lists, forItems, event, $context, $w, params) => {${bindMeta.imports} return(
      ${bindMeta.expression === '' ? 'undefined': bindMeta.expression}
    )}`
    list.push(str)
  })
  return list.join(',')
}%>
<% function printEventHandler(eventHandlers) {
  /**
   * TODO: copy 过来的代码
   * 一些模板层面的工具应该如何复用？
   */
  Object.entries(eventHandlers).map(([handlerName, listeners])=>{
    print(`"${handlerName}": [
      ${listeners.map(l=>{
        return `{
          key: '${l.key||''}',
          sourceKey: '${ l.sourceKey||"" }',
          handler: ${l.generateHandler(subLevelPath) || 'undefined'},
          args: ${JSON.stringify(l.args||{}, undefined, 2)},
          argsBinds: {${printBoundData(l.argsBinds)}}
        }`
      }).join(',')}
    ],`)
  })
}%>

export const app = createGlboalApi()
export const $app = new Proxy({}, { get: function(obj, prop){ return app[prop] }});
export const $w = new Proxy(
  {},
  {
    get(_, prop) {
      return app.__internal__.$w?.[prop];
    },
  },
);

globalThis.__wedaGlobal__ = new Proxy({
  app,
  $w
}, {
  get(_, prop) {
    switch(prop) {
      case 'app':
      case '$app':
        return app
      case '$w':
        return $w
    }
    return undefined
  }
})

function createGlboalApi() {
  const mpApp = createMpApp({
    appConfig: {
      staticResourceDomain: config.domain,
      privatelink: cloudConfig.privatelink,
      envVersion: cloudConfig.isProd ? 'production' : 'preview',
      ...(<%= appConfig %>)
    },
  });
  const globalAPI = Object.assign(mpApp, {
    state: observable(state),
    computed: createComputed(computed),
    common,
    ...mpApp,
    // ... other sdk apis & apis from mp
  }) // The global api exposed to lowcode

  /**
   * @deprecated utils._getConfig
   */
  globalAPI.utils._getConfig = () => {
    return globalAPI.__internal__.getConfig()
  }

  let dataset = createDataset('$global', undefined, {
    appId: globalAPI.id
  })
  dataset.query = generateDatasetQuery({<% Object.entries(appQuery).map(([id, item])=>{%>
    <%= id %>: { <% const { dataBinds, eventHandlers, handler, ...rest } = item %>
      ...(<%= JSON.stringify(rest, undefined, 2) %>),
      handler: <%= handler %>,
      dataBinds: {<%= printBoundData(dataBinds) %>},
      eventHandlers: {<% printEventHandler(eventHandlers) %>}
    },<%}) %>
  }, {
    $app: globalAPI,
    $w: globalAPI.__internal__.$w,
  })

  GLOBAL_DATASET_SYNC_DISPOSES.forEach((dispose) => {
    dispose?.();
  });
  GLOBAL_DATASET_SYNC_DISPOSES = [];
  globalAPI.dataset = dataset
  GLOBAL_DATASET_SYNC_DISPOSES = watchAndSyncDatasetState2Local(globalAPI.id, '$global', globalAPI.dataset.state);

  globalAPI.state.dataset = dataset
  globalAPI.setState = (userSetState) => {
    Object.keys(userSetState).forEach((keyPath) => {
      globalAPI.utils.set(globalAPI.dataset.state, keyPath, userSetState[keyPath]);
    });
  };

  const subPackageName = '<%= subPackageName %>'
  if (subPackageName) {
    // is sub app
    globalAPI.mainApp = appGlobal[mainAppKey]
    const mpApp = getApp()
    mpApp && (mpApp.subApp = globalAPI)
  } else {
    // is mainApp
    appGlobal[mainAppKey] = globalAPI
  }

  // # expose some sdk modules
  /* const sdkModsIncluded = ['flow', 'getPageOptions', 'getLaunchOptions']
  sdkModsIncluded.forEach(key => {
    globalAPI[key] = sdk[key]
  }) */

  return globalAPI
}
