import login from './login'

const modules = [login]

function isPlainObject(v) {
  return v != null && typeof v === 'object' && !Array.isArray(v)
}

function mergeDeep(target, source) {
  const out = { ...(isPlainObject(target) ? target : {}) }
  if (!isPlainObject(source)) return out

  for (const key of Object.keys(source)) {
    const sv = source[key]
    const tv = out[key]
    if (isPlainObject(tv) && isPlainObject(sv)) out[key] = mergeDeep(tv, sv)
    else out[key] = sv
  }
  return out
}

function mergeShallowWithDevWarn(target, source, label) {
  const t = isPlainObject(target) ? target : {}
  const s = isPlainObject(source) ? source : {}

  if (typeof __DEV__ !== 'undefined' && __DEV__) {
    for (const key of Object.keys(s)) {
      if (Object.prototype.hasOwnProperty.call(t, key)) {
        if (t[key] !== s[key]) {
          console.warn(`[brand-modules] ${label}.${key} 被后续模块覆盖`)
        }
      }
    }
  }

  return { ...t, ...s }
}

function mergeBrandModules(modules) {
  const base = { features: { theme: { primary: '#DE428C' } }, components: {}, overrides: {}, assets: {} }
  return modules.reduce((acc, m) => {
    if (!m) return acc
    const patch = typeof m === 'function' ? m(acc) : m
    if (!patch) return acc
    const namespace = typeof patch.namespace === 'string' && patch.namespace ? patch.namespace : null

    const featuresPatch = (() => {
      if (!patch.features) return null
      if (!namespace) return patch.features
      if (isPlainObject(patch.features) && Object.prototype.hasOwnProperty.call(patch.features, namespace)) return patch.features
      return { [namespace]: patch.features }
    })()

    const componentsNext = (() => {
      if (!patch.components) return acc.components
      if (!namespace) return mergeShallowWithDevWarn(acc.components, patch.components, 'components')
      const prevScope = acc.components?.[namespace]
      const nextScope = mergeShallowWithDevWarn(prevScope, patch.components, `components.${namespace}`)
      return { ...acc.components, [namespace]: nextScope }
    })()

    const overridesNext = (() => {
      if (!patch.overrides) return acc.overrides
      if (!namespace) return mergeShallowWithDevWarn(acc.overrides, patch.overrides, 'overrides')
      const prevScope = acc.overrides?.[namespace]
      const nextScope = mergeShallowWithDevWarn(prevScope, patch.overrides, `overrides.${namespace}`)
      return { ...acc.overrides, [namespace]: nextScope }
    })()

    const assetsNext = (() => {
      const rootPatch = patch.assetsRoot
      const rootNext = rootPatch ? mergeShallowWithDevWarn(acc.assets, rootPatch, 'assets') : acc.assets
      if (!patch.assets) return rootNext
      if (!namespace) return mergeShallowWithDevWarn(rootNext, patch.assets, 'assets')
      const prevScope = rootNext?.[namespace]
      const nextScope = mergeShallowWithDevWarn(prevScope, patch.assets, `assets.${namespace}`)
      return { ...rootNext, [namespace]: nextScope }
    })()

    return {
      features: featuresPatch ? mergeDeep(acc.features, featuresPatch) : acc.features,
      components: componentsNext,
      overrides: overridesNext,
      assets: assetsNext,
    }
  }, base)
}

const brand = mergeBrandModules(modules)

export const features = brand.features
export const components = brand.components
export const overrides = brand.overrides
export const assets = brand.assets

export default brand
