import { log }          from '@juzi/wechaty-puppet'

import {
  ContactImpl,
  ContactSelfImpl,
  DelayImpl,
  FriendshipImpl,
  ImageImpl,
  LocationImpl,
  MessageImpl,
  MiniProgramImpl,
  PostImpl,
  RoomImpl,
  RoomInvitationImpl,
  TagImpl,
  TagGroupImpl,
  UrlLinkImpl,
  ChannelImpl,
  ChannelCardImpl,
  ConsultCardImpl,
  PremiumOnlineAppointmentCardImpl,
  MomentImpl,
  CallRecordImpl,
  ChatHistoryImpl,
  WecomImpl,
  DouyinOneClickPhoneCollectionImpl,
  ImSpecificImpl,
  WxxdProductImpl,
  WxxdOrderImpl,

  ContactConstructor,
  ContactSelfConstructor,
  DelayConstructor,
  FriendshipConstructor,
  ImageConstructor,
  LocationConstructor,
  MessageConstructor,
  MiniProgramConstructor,
  PostConstructor,
  RoomConstructor,
  RoomInvitationConstructor,
  TagConstructor,
  TagGroupConstructor,
  UrlLinkConstructor,
  ChannelConstructor,
  ChannelCardConstructor,
  ConsultCardConstructor,
  PremiumOnlineAppointmentCardConstructor,
  MomentConstructor,
  CallRecordConstructor,
  ChatHistoryConstructor,
  WecomConstructor,
  DouyinOneClickPhoneCollectionConstructor,
  ImSpecificConstructor,
  WxxdProductConstructor,
  WxxdOrderConstructor,
  wechatifyUserModule,
}                       from '../user-modules/mod.js'

import type {
  WechatySkeleton,
}                             from '../wechaty/mod.js'

const wechatifyUserModuleMixin = <MixinBase extends typeof WechatySkeleton> (mixinBase: MixinBase) => {
  log.verbose('WechatifyUserModuleMixin', 'wechatifyUserModuleMixin(%s)', mixinBase.name)

  abstract class WechatifyUserModuleMixin extends mixinBase {

    constructor (...args: any[]) {
      log.verbose('WechatifyUserModuleMixin', 'constructor()')
      super(...args)
    }

    __wechatifiedContact?                       : ContactConstructor
    __wechatifiedContactSelf?                   : ContactSelfConstructor
    __wechatifiedDelay?                         : DelayConstructor
    __wechatifiedFriendship?                    : FriendshipConstructor
    __wechatifiedImage?                         : ImageConstructor
    __wechatifiedLocation?                      : LocationConstructor
    __wechatifiedMessage?                       : MessageConstructor
    __wechatifiedMiniProgram?                   : MiniProgramConstructor
    __wechatifiedPost?                          : PostConstructor
    __wechatifiedRoom?                          : RoomConstructor
    __wechatifiedRoomInvitation?                : RoomInvitationConstructor
    __wechatifiedTag?                           : TagConstructor
    __wechatifiedTagGroup?                      : TagGroupConstructor
    __wechatifiedUrlLink?                       : UrlLinkConstructor
    __wechatifiedChannel?                       : ChannelConstructor
    __wechatifiedChannelCard?                   : ChannelCardConstructor
    __wechatifiedConsultCard?                   : ConsultCardConstructor
    __wechatifiedPremiumOnlineAppointmentCard?  : PremiumOnlineAppointmentCardConstructor
    __wechatifiedMoment?                        : MomentConstructor
    __wechatifiedCallRecord?                    : CallRecordConstructor
    __wechatifiedChatHistory?                   : ChatHistoryConstructor
    __wechatifiedWecom?                         : WecomConstructor
    __wechatifiedDouyinOneClickPhoneCollection? : DouyinOneClickPhoneCollectionConstructor
    __wechatifiedImSpecific?                    : ImSpecificConstructor
    __wechatifiedWxxdProduct?                   : WxxdProductConstructor
    __wechatifiedWxxdOrder?                     : WxxdOrderConstructor

    get Contact ()                      : ContactConstructor                        { return guardWechatify(this.__wechatifiedContact)        }
    get ContactSelf ()                  : ContactSelfConstructor                    { return guardWechatify(this.__wechatifiedContactSelf)    }
    get Delay ()                        : DelayConstructor                          { return guardWechatify(this.__wechatifiedDelay)          }
    get Friendship ()                   : FriendshipConstructor                     { return guardWechatify(this.__wechatifiedFriendship)     }
    get Image ()                        : ImageConstructor                          { return guardWechatify(this.__wechatifiedImage)          }
    get Location ()                     : LocationConstructor                       { return guardWechatify(this.__wechatifiedLocation)       }
    get Message ()                      : MessageConstructor                        { return guardWechatify(this.__wechatifiedMessage)        }
    get MiniProgram ()                  : MiniProgramConstructor                    { return guardWechatify(this.__wechatifiedMiniProgram)    }
    get Post ()                         : PostConstructor                           { return guardWechatify(this.__wechatifiedPost)           }
    get Room ()                         : RoomConstructor                           { return guardWechatify(this.__wechatifiedRoom)           }
    get RoomInvitation ()               : RoomInvitationConstructor                 { return guardWechatify(this.__wechatifiedRoomInvitation) }
    get Tag ()                          : TagConstructor                            { return guardWechatify(this.__wechatifiedTag)            }
    get TagGroup ()                     : TagGroupConstructor                       { return guardWechatify(this.__wechatifiedTagGroup)       }
    get UrlLink ()                      : UrlLinkConstructor                        { return guardWechatify(this.__wechatifiedUrlLink)        }
    get Channel ()                      : ChannelConstructor                        { return guardWechatify(this.__wechatifiedChannel)        }
    get ChannelCard ()                  : ChannelCardConstructor                    { return guardWechatify(this.__wechatifiedChannelCard)    }
    get ConsultCard ()                  : ConsultCardConstructor                    { return guardWechatify(this.__wechatifiedConsultCard)    }
    get PremiumOnlineAppointmentCard () : PremiumOnlineAppointmentCardConstructor   { return guardWechatify(this.__wechatifiedPremiumOnlineAppointmentCard) }
    get Moment ()                       : MomentConstructor                         { return guardWechatify(this.__wechatifiedMoment)         }
    get CallRecord ()                   : CallRecordConstructor                     { return guardWechatify(this.__wechatifiedCallRecord)     }
    get ChatHistory ()                  : ChatHistoryConstructor                    { return guardWechatify(this.__wechatifiedChatHistory)    }
    get Wecom ()                        : WecomConstructor                          { return guardWechatify(this.__wechatifiedWecom)          }
    get DouyinOneClickPhoneCollection () : DouyinOneClickPhoneCollectionConstructor { return guardWechatify(this.__wechatifiedDouyinOneClickPhoneCollection) }
    get ImSpecific ()                    : ImSpecificConstructor                    { return guardWechatify(this.__wechatifiedImSpecific)      }
    get WxxdProduct ()                   : WxxdProductConstructor                   { return guardWechatify(this.__wechatifiedWxxdProduct)     }
    get WxxdOrder ()                     : WxxdOrderConstructor                     { return guardWechatify(this.__wechatifiedWxxdOrder)       }

    override async init (): Promise<void> {
      log.verbose('WechatifyUserModuleMixin', 'init()')
      await super.init()

      /**
       * Skip if already wechatified
       */
      if (this.__wechatifiedMessage) {
        log.verbose('WechatifyUserModuleMixin', 'init() Wechaty User Module (WUM)s have already wechatified: skip')
        return
      }

      log.verbose('WechatifyUserModuleMixin', 'init() initializing Wechaty User Module (WUM) ...')

      /**
       * Wechatify User Classes
       *  1. Binding the wechaty instance to the class
       *
       * Huan(202110): FIXME: remove any
       */
      this.__wechatifiedContact                      = wechatifyUserModule(ContactImpl)(this as any)
      this.__wechatifiedContactSelf                  = wechatifyUserModule(ContactSelfImpl)(this as any)
      this.__wechatifiedDelay                        = wechatifyUserModule(DelayImpl)(this as any)
      this.__wechatifiedFriendship                   = wechatifyUserModule(FriendshipImpl)(this as any)
      this.__wechatifiedImage                        = wechatifyUserModule(ImageImpl)(this as any)
      this.__wechatifiedLocation                     = wechatifyUserModule(LocationImpl)(this as any)
      this.__wechatifiedMessage                      = wechatifyUserModule(MessageImpl)(this as any)
      this.__wechatifiedMiniProgram                  = wechatifyUserModule(MiniProgramImpl)(this as any)
      this.__wechatifiedPost                         = wechatifyUserModule(PostImpl)(this as any)
      this.__wechatifiedRoom                         = wechatifyUserModule(RoomImpl)(this as any)
      this.__wechatifiedRoomInvitation               = wechatifyUserModule(RoomInvitationImpl)(this as any)
      this.__wechatifiedTag                          = wechatifyUserModule(TagImpl)(this as any)
      this.__wechatifiedTagGroup                     = wechatifyUserModule(TagGroupImpl)(this as any)
      this.__wechatifiedUrlLink                      = wechatifyUserModule(UrlLinkImpl)(this as any)
      this.__wechatifiedChannel                      = wechatifyUserModule(ChannelImpl)(this as any)
      this.__wechatifiedChannelCard                  = wechatifyUserModule(ChannelCardImpl)(this as any)
      this.__wechatifiedConsultCard                  = wechatifyUserModule(ConsultCardImpl)(this as any)
      this.__wechatifiedPremiumOnlineAppointmentCard = wechatifyUserModule(PremiumOnlineAppointmentCardImpl)(this as any)
      this.__wechatifiedMoment                       = wechatifyUserModule(MomentImpl)(this as any)
      this.__wechatifiedCallRecord                   = wechatifyUserModule(CallRecordImpl)(this as any)
      this.__wechatifiedChatHistory                  = wechatifyUserModule(ChatHistoryImpl)(this as any)
      this.__wechatifiedWecom                        = wechatifyUserModule(WecomImpl)(this as any)
      this.__wechatifiedDouyinOneClickPhoneCollection = wechatifyUserModule(DouyinOneClickPhoneCollectionImpl)(this as any)
      this.__wechatifiedImSpecific                    = wechatifyUserModule(ImSpecificImpl)(this as any)
      this.__wechatifiedWxxdProduct                   = wechatifyUserModule(WxxdProductImpl)(this as any)
      this.__wechatifiedWxxdOrder                     = wechatifyUserModule(WxxdOrderImpl)(this as any)

      log.verbose('WechatifyUserModuleMixin', 'init() initializing Wechaty User Module (WUM) ... done')
    }

  }

  return WechatifyUserModuleMixin
}

/**
 * Huan(202008): we will bind the wechaty puppet with user modules (Contact, Room, etc) together inside the start() method
 */
function guardWechatify<T extends Function> (userModule?: T): T {
  if (userModule) {
    return userModule
  }
  throw new Error('Wechaty User Module (WUM, for example: wechaty.Room) can not be used before wechaty.start()!')
}

type WechatifyUserModuleMixin = ReturnType<typeof wechatifyUserModuleMixin>

type ProtectedPropertyWechatifyUserModuleMixin =
  | '__wechatifiedContact'
  | '__wechatifiedContactSelf'
  | '__wechatifiedDelay'
  | '__wechatifiedFriendship'
  | '__wechatifiedImage'
  | '__wechatifiedLocation'
  | '__wechatifiedMessage'
  | '__wechatifiedMiniProgram'
  | '__wechatifiedRoom'
  | '__wechatifiedRoomInvitation'
  | '__wechatifiedTag'
  | '__wechatifiedTagGroup'
  | '__wechatifiedUrlLink'
  | '__wechatifiedChannel'
  | '__wechatifiedChannelCard'
  | '__wechatifiedConsultCard'
  | '__wechatifiedPremiumOnlineAppointmentCard'
  | '__wechatifiedMoment'
  | '__wechatifiedCallRecord'
  | '__wechatifiedChatHistory'
  | '__wechatifiedWecom'
  | '__wechatifiedDouyinOneClickPhoneCollection'
  | '__wechatifiedImSpecific'
  | '__wechatifiedWxxdProduct'
  | '__wechatifiedWxxdOrder'

export type {
  WechatifyUserModuleMixin,
  ProtectedPropertyWechatifyUserModuleMixin,
}
export {
  wechatifyUserModuleMixin,
}
