import AV from 'leancloud-storage'
import LCQuery from './query'
import LCObject from './object'
import LCUser from './user'
import LCRole from './role'
import LCACL from './acl'
import LCFile from './file'
import LCRelation from './relation'

class InterceptorManger {
  handlers = []
  use(fulfilled, rejected) {
    this.handlers.push(fulfilled, rejected)
  }
}

class LC {
  interceptors = {
    request: new InterceptorManger(),
    response: new InterceptorManger(),
  }

  constructor(initData, defaultACL) {
    AV.init({
      ...initData,
    })
    this.AV = AV
    this.defaultACL = defaultACL
      ? this.ACL().createACL(defaultACL).avObject
      : null
  }

  request(dispatchRequest) {
    let promise = Promise.resolve(this)
    let chain = [dispatchRequest, undefined]

    const requestInterceptorChain = []
    const [...handlers] = this.interceptors.request.handlers
    while (handlers.length > 0) {
      requestInterceptorChain.unshift(handlers.shift(), handlers.shift())
    }
    Array.prototype.unshift.apply(chain, requestInterceptorChain)
    chain = chain.concat(this.interceptors.response.handlers)
    while (chain.length > 0) {
      promise = promise
        .then(chain.shift(), chain.shift())
        .catch((err) => Promise.reject(err))
    }
    return promise
  }

  Object(className) {
    return new LCObject(AV, className, this.defaultACL, this.request, this)
  }

  Query(className) {
    return new LCQuery(AV, className, this.request, this)
  }

  User() {
    return new LCUser(AV, this.defaultACL, this.request, this)
  }

  Role(name, acl) {
    const { defaultACL } = this
    const ACL = acl || defaultACL
    return new LCRole(AV, name, ACL, this.request, this)
  }

  ACL() {
    return new LCACL(AV, this.request, this)
  }

  File(filename, file, contentType) {
    return new LCFile(AV, filename, file, contentType, this.request, this)
  }

  Relation(parent, key) {
    return new LCRelation(AV, parent, key, this.request, this)
  }
}

export default LC
