import Dream from "../Dream"
import { FPShapeOfRectV2 } from "../Dream/UI"
import { layers } from "./layers"
import { UseAni } from "./UseDecorator/useAni"

type UseAniConfig = {
  showCall?: (c: FYGE.Container, ...args: any[]) => Promise<any>
  hideCall?: (c: FYGE.Container) => Promise<any>
}

type ShowModalType = {
  center: boolean,
  maskAlpha: number
  destroy: boolean
} & UseAniConfig

const defaultModalConfig:ShowModalType = {
  center: true,
  maskAlpha: 0.7,
  destroy: true,
  showCall: fadeIn,
  hideCall: fadeOut
}

function fadeIn(cont: FYGE.Container) {
  return new Promise(r => {
    FYGE.Tween.removeTweens(cont)
    FYGE.Tween.get(cont)
      .set({alpha: 0})
      .to({
        alpha: 1
      }, 300, FYGE.Ease.quadIn)
      .call(r)
  })
}

function getBoundsPropty(Con: FYGE.Container, proptyName: string): any {
  // @ts-ignore
  return Con[proptyName] || (Con.children.length == 1 ? getBoundsPropty(Con.children[0] as FYGE.Container, proptyName) : Con[proptyName])
}

function fadeOut(cont: FYGE.Container) {
  return new Promise(r => {
    FYGE.Tween.removeTweens(cont)
    FYGE.Tween.get(cont)
      .to({
        alpha: 0
      }, 300, FYGE.Ease.quadIn)
      .call(r)
  })
}

function ModalWraper(ModalNode: any) {
  return class extends Dream.RenderContainer {
    ModalContainer: FYGE.Container
    ModalBody: FYGE.Container
    maskAniCont: { show: () => Promise<any>; hide: () => Promise<any> }
    ModalBodyAniCont: any

    didRendered() {
      this.onAdjustPos()
    }

    /**
     * 自适应布局
     */
    onAdjustPos() {
      const ModalConfig = this.props._config
      // 这里做了 适配，不知道为什么 有些拿不到宽高
      if (ModalConfig?.center) {
        const body = this.ModalBody
        // TODO 这里好像算的有点问题多 20
        const sw = body.sw || getBoundsPropty(body, 'width') - 20
        const sh = body.sh || getBoundsPropty(body, 'height') - 20
        this.ModalBody.position.set(layers.stageWidth / 2 - sw / 2, layers.stageHeight / 2 - sh / 2)
      }
    }

    showModal = async () => {
      const _ModalContainer = this.ModalContainer
      this.ModalContainer?.parent?.addChild(_ModalContainer)
      _ModalContainer.visible = true

      await Promise.all([
        this.maskAniCont.show(),
        this.ModalBodyAniCont.show()
      ])
    }

    hideModal = async() => {
      const _ModalContainer = this.ModalContainer
      await Promise.all([
        this.maskAniCont.hide(),
        this.ModalBodyAniCont.hide()
      ])
      _ModalContainer.visible = false
    }

    unMount(): void {
    }

    render() {
      const {
        maskAlpha = 0.7,
        showCall,
        hideCall
      } = this.props._config

      const {_config, ...otherProps} = this.props

      const MaskCont: any = UseAni({
        showCall: fadeIn,
        hideCall: fadeOut
      })(FPShapeOfRectV2)

      const onAdjustPosInvoke = this.onAdjustPos.bind(this)
      const ModalBodyAniCont = UseAni({
        showCall,
        hideCall
      })(function() {
        return (
          <ModalNode {...otherProps} onLoaded={() => {
            // 加载完成后重新 布局
            onAdjustPosInvoke()
          }} ref={(el: any) => {
            this.AniCont = el
          }}></ModalNode>
        )
      })

      return (
        <FYGE.Container inlineProps={{
          y: layers.stageOffsetY
        }} ref={(el: FYGE.Container) => {
          this.ModalContainer = el
        }}>
          <MaskCont getAniIns={(ins: { show: () => Promise<any>; hide: () => Promise<any> }) => {
            this.maskAniCont = ins
          }} alpha={maskAlpha}></MaskCont>

          <FYGE.Container ref={(el: any) => {
            this.ModalBody = el
          }}>
            <ModalBodyAniCont getAniIns={ins => {
              this.ModalBodyAniCont = ins
            }}></ModalBodyAniCont>
          </FYGE.Container>
        </FYGE.Container>
      )
    }
  }
}

export const ModalCtroller = (function() {
  const ModalMap = new Map()
  return {
    showModal(ModalNode: any, props?: Record<string, any>, config?: Partial<ShowModalType>) {
      const _ = ModalMap.get(ModalNode)
      const _config = Object.assign({}, defaultModalConfig, config)
      if (_) {
        _.showModal(_config)
        return
      }

      const M = ModalWraper(ModalNode)
      const cont = new FYGE.Container()
      layers.popupLayer.addChild(cont)
      console.log('new Modal render')
      Dream.VirtualRender(cont, <M
        {...props}
        _config={_config}
        ref={(el: { showModal: () => void }) => {
          ModalMap.set(ModalNode, el)
          el.showModal()
        }}
        closeModal={async () => {
          await ModalCtroller.closeModal(ModalNode)
        }}
      ></M>)
    },
    async closeModal(ModalNode: any) {
      const _ = ModalMap.get(ModalNode)
      if (_) {
        await _.hideModal()
        const {
          destroy
        } = (_.props._config as ShowModalType)
        if (destroy) {
          _.ModalContainer.parent.removeChild(_.ModalContainer);
          (_.ModalContainer as FYGE.Container).destroy();
          ModalMap.delete(ModalNode)
        }
        // console.log('closeModal config:', _.props._config, ModalMap)
        
        return
      }
    },
    closeAllModal() {
      ModalMap.forEach(item => {
        item.closeModal && item.closeModal()
      })
    },
    clearModalMap() {
      ModalMap.clear()
    }
  }
})()