/**
 * Copyright (c) 2023 - present TinyEngine Authors.
 * Copyright (c) 2023 - present Huawei Cloud Computing Technologies Co., Ltd.
 *
 * Use of this source code is governed by an MIT-style license.
 *
 * THE OPEN SOURCE SOFTWARE IN THIS PRODUCT IS DISTRIBUTED IN THE HOPE THAT IT WILL BE USEFUL,
 * BUT WITHOUT ANY WARRANTY, WITHOUT EVEN THE IMPLIED WARRANTY OF MERCHANTABILITY OR FITNESS FOR
 * A PARTICULAR PURPOSE. SEE THE APPLICABLE LICENSES FOR MORE DETAILS.
 *
 */

/* metaService: engine.service.resource.useResource */
import { reactive, toRaw } from 'vue'
import { constants } from '@opentiny/tiny-engine-utils'
import { getCanvasStatus } from '@opentiny/tiny-engine-common/js/canvas'
import {
  useCanvas,
  useTranslate,
  useBreadcrumb,
  useLayout,
  useBlock,
  useMaterial,
  getMetaApi,
  META_APP,
  useMessage,
  META_SERVICE
} from '@opentiny/tiny-engine-meta-register'

const { COMPONENT_NAME, DEFAULT_INTERCEPTOR } = constants

interface AppSchemaState {
  dataSource: any[]
  pageTree: any[]
  langs: {
    locales: {
      lang: string
    }[]
    messages: any
  }
  utils: { [x: string]: any; type: string }[]
  globalState: any[]
  materialsDeps: {
    scripts: any[]
    styles: Set<unknown>
  }
  componentsMap?: any
  dataHandler?: any
  willFetch?: any
  errorHandler?: any
  bridge?: any
  isDemo?: boolean
}

const appSchemaState = reactive<AppSchemaState>({
  dataSource: [],
  pageTree: [],
  langs: { locales: [], messages: {} },
  utils: [],
  globalState: [],
  materialsDeps: { scripts: [], styles: new Set() }
})

function goPage(pageId: string) {
  if (!pageId) {
    return
  }

  getMetaApi(META_SERVICE.GlobalService).updatePageId(pageId)
}

interface PageInfo {
  [x: string]: any
  meta: any
  id: string
  fileName: string
  componentName: string
  props: any
}

const initPage = (pageInfo: PageInfo) => {
  try {
    // 有id,说明不是临时的页面
    if (pageInfo?.id || typeof pageInfo?.id === 'number') {
      useLayout().layoutState.pageStatus = getCanvasStatus(pageInfo.occupier)
      goPage(pageInfo.id)
    } else {
      useLayout().layoutState.pageStatus = {
        state: 'empty',
        data: {}
      }
    }
  } catch (error) {
    console.log(error) // eslint-disable-line
  }

  useCanvas().initData(pageInfo?.page_content || {}, pageInfo)
  useBreadcrumb().setBreadcrumbPage([pageInfo?.name || ''])
}

/**
 * 根据区块 id 初始化应用
 * @param {string} blockId 区块 id
 */
const initBlock = async (blockId: string) => {
  const blockApi = getMetaApi(META_APP.BlockManage)
  const blockContent = await blockApi.getBlockById(blockId)

  if (blockContent.public_scope_tenants?.length) {
    blockContent.public_scope_tenants = blockContent.public_scope_tenants.map((e: { id: string }) => e.id)
  }

  useLayout().layoutState.pageStatus = getCanvasStatus(blockContent?.occupier)

  // 请求区块详情
  useBlock().initBlock(blockContent, {}, true)
}

const initPageOrBlock = async () => {
  const { pageId, blockId } = getMetaApi(META_SERVICE.GlobalService).getBaseInfo()
  const pagePluginApi = getMetaApi(META_APP.AppManage)
  const userInfo = getMetaApi(META_SERVICE.GlobalService).getUserInfo()

  if (pageId) {
    const data = await pagePluginApi.getPageById(pageId)
    initPage(data)
    return
  }

  if (blockId) {
    await initBlock(blockId)

    return
  }

  // url 没有 pageid 或 blockid,页面打开顺序:可访问主页 -> 可访问的第一个页面 -> 不可访问首页 -> 不可访问全页面顺位第一页
  const getPageInfo = () => {
    // 页面是否被他人锁定 (被锁定 且 非当前用户锁定)
    const isPageOccupierdByOthers = (page) => {
      return page.meta?.occupier && page.meta.occupier.id !== userInfo.id
    }
    // 首页
    const homePage = appSchemaState.pageTree.find((page) => page?.meta?.isHome)
    // 顺位首个页面
    const firstPage = appSchemaState.pageTree.find(
      (page) => page.componentName === COMPONENT_NAME.Page && page?.meta?.group !== 'publicPages'
    )
    // 顺位首个可访问页面(当前用户锁定 或 未锁定)
    const firstUnoccupiedPage = appSchemaState.pageTree.find(
      (page) =>
        page.componentName === COMPONENT_NAME.Page &&
        page?.meta?.group !== 'publicPages' &&
        !isPageOccupierdByOthers(page)
    )
    // 空页面
    const emptyPage = {
      page_content: {
        componentName: COMPONENT_NAME.Page
      }
    }
    // 可访问主页 (当前用户锁定 或 未锁定)
    if (homePage && !isPageOccupierdByOthers(homePage)) {
      return homePage
    }
    return firstUnoccupiedPage || homePage || firstPage || emptyPage
  }
  const pageInfo = getPageInfo()

  if (pageInfo.meta?.id) {
    // 这里重新请求一遍页面详情数据,是因为 appSchemaState 的页面信息存在字段转换,比如 route 被转换成了 router 字段,导致调用页面保存接口的时候报错
    const data = await pagePluginApi.getPageById(pageInfo.meta.id)
    initPage(data)
  } else {
    initPage(toRaw(pageInfo))
  }
}

const handlePopStateEvent = async () => {
  const { id, type } = getMetaApi(META_SERVICE.GlobalService).getBaseInfo()

  await initPageOrBlock()

  // 国际化貌似有 app 和区块之分,但是目前其实都存到了 app 里面,需要确认是否需要修复
  await useTranslate().initI18n({ host: id, hostType: type })
}

const fetchAppState = async () => {
  const { id } = getMetaApi(META_SERVICE.GlobalService).getBaseInfo()
  const appData = await getMetaApi(META_SERVICE.Http).get(`/app-center/v1/api/apps/schema/${id}`)
  appSchemaState.pageTree = appData.componentsTree
  appSchemaState.componentsMap = appData.componentsMap
  appSchemaState.dataSource = appData.dataSource?.list
  appSchemaState.dataHandler = appData.dataSource?.dataHandler || DEFAULT_INTERCEPTOR.dataHandler
  appSchemaState.willFetch = appData.dataSource?.willFetch || DEFAULT_INTERCEPTOR.willFetch
  appSchemaState.errorHandler = appData.dataSource?.errorHandler || DEFAULT_INTERCEPTOR.errorHandler

  appSchemaState.bridge = appData.bridge
  appSchemaState.utils = appData.utils
  appSchemaState.isDemo = appData?.meta?.isDemo || appData?.meta?.is_demo
  appSchemaState.globalState = appData?.meta?.globalState || appData?.meta?.global_state

  // 词条语言为空时使用默认的语言
  const defaultLocales = [
    { lang: 'zh_CN', label: 'zh_CN' },
    { lang: 'en_US', label: 'en_US' }
  ]
  const locales = Object.keys(appData.i18n).length
    ? Object.keys(appData.i18n).map((key) => ({ lang: key, label: key }))
    : defaultLocales

  appSchemaState.langs = {
    locales,
    messages: appData.i18n
  }

  return appData
}

const fetchResource = async ({ isInit = true } = {}) => {
  const { id, type } = getMetaApi(META_SERVICE.GlobalService).getBaseInfo()
  useMessage().publish({ topic: 'app_id_changed', data: id })

  const appData = await fetchAppState()

  useMaterial().initMaterial({ isInit, appData })

  try {
    await useMaterial().fetchMaterial()

    if (isInit) {
      await initPageOrBlock()
    }

    await useTranslate().initI18n({ host: id, hostType: type, init: true })
  } catch (error) {
    console.log(error) // eslint-disable-line
  }
}

// 获取工具类的依赖,用于预览加载。格式和物料依赖一致,便于处理
const getUtilsDeps = () => {
  return appSchemaState.utils
    .filter((item) => item.type === 'npm')
    .map((item) => {
      return {
        ...item,
        package: item.content?.package,
        script: item.content?.cdnLink
      }
    })
}

export default function () {
  return {
    appSchemaState,
    getUtilsDeps,
    fetchResource,
    initPageOrBlock,
    handlePopStateEvent,
    fetchAppState
  }
}