const PENDING = 'pending'
const FULFILLED = 'fulfilled'
const REJECTED = 'rejected'

class MyPromise {
  constructor(executor) {
    // executor是一个执行器,进入会立即执行
    // 传入resolve和reject
    // 检测传入的代码体出错
    try {
      executor(this.resolve, this.reject)
    } catch (error) {
      this.reject(error)      
    }
  }

  // 为实例定义属性 status、value、reason
  // 存储状态码变量,初始值是pending
  status = PENDING
  // 成功之后的值
  value = null
  // 失败之后的原因
  reason = null
  // 存储成功回调函数
  onFulfilledCallback = []
  // 存储失败回调函数
  onRejectedCallback = []

  // 箭头函数让方法内部this指向当前实例
  // 更改成功后的状态
  resolve = (value) => {
    // 只有状态时等待,才执行状态修改
    if (this.status === PENDING) {
      // 状态修改成功
      this.status = FULFILLED
      // 保存成功的值
      this.value = value
      // 判断回调函数是否存在,有则调用
      while(this.onFulfilledCallback.length) {
        this.onFulfilledCallback.shift()(value)
      }
    }
  }
  // 同理响应失败流程
  reject = (reason) => {
    if (this.status === PENDING) {
      this.status = REJECTED
      this.reason = reason
      while(this.onRejectedCallback.length) {
        this.onRejectedCallback.shift()(reason)
      }
    }
  }
  
  then(onFulfilled, onRejected) {
    // 如果不传,就使用默认函数
    onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : value => value;
    onRejected = typeof onRejected === 'function' ? onRejected : reason => {throw reason};
    // 为了链式调用创建一个MyProise并在后面return出去
    const nextPromise = new MyPromise((resolve, reject) => {
      // 这里的内容在执行器中,会立即执行
      if (this.status === FULFILLED) {
        // 创建一个微任务等待 nextPromise 完成初始化
        queueMicrotask(() => {
          try {
            // 获取成功回调函数的执行结果
            const x = onFulfilled(this.value)
            // 传入 resolvePromise 集中处理
            resolvePromise(nextPromise, x, resolve, reject)
          } catch (error) {
            reject(error)            
          }
        })  
      } else if (this.status === REJECTED) {
        queueMicrotask(() => {
          try {
            const x = onRejected(this.reason)
            resolvePromise(nextPromise, x, resolve, reject)
          } catch (error) {
            reject(error)
          }
        })
      } else if (this.status === PENDING) {
        // 当promise中是异步时,并未进行状态的变更,此时then还是pending状态
        // 此时将回调暂时存储起来
        this.onFulfilledCallback.push(onFulfilled)
        this.onRejectedCallback.push(onRejected)
      }
    })
    return nextPromise
  }

  // 直接Promise.resolve
  // 定义静态属性
  static resolve(parameter) {
    // 如果传入promise直接返回
    if (parameter instanceof MyPromise) {
      return parameter
    }
    // 转成常规方式
    return new MyPromise(resolve => {
      resolve(parameter)
    })
  }

  // 定义reject
  static reject(reason) {
    return new MyPromise((resolve, reject) => {
      reject(reason)
    })
  }
}

const resolvePromise = (nextPromise, x, resolve, reject) => {
  // 如果相等了,说明return的是自己,抛出类型错误并返回
  if (nextPromise === x) {
    return reject(new TypeError('Chaining cycle detected for promise #<Promise>'))
  }
  // 判断x是不是promise对象
  if (x instanceof MyPromise) {
    // 执行x,调用then方法,目的是将其状态改变为fulfilled或者rejeacted
    // x.then(value => resolve(value), reason => reject(reason))
    x.then(resolve, reject)
  } else {
    resolve(x)
  }
}

module.exports = MyPromise

MyPromise.prototype.finally = function(cb) {
  return this.then(
    value => MyPromise.resolve(cb()).then(() => value),
    reason => MyPromise.reject(cb()).then(() => { throw reason })
  )
}

MyPromise.all = (lists) => {
  // 返回一个promise
  return new MyPromise((resolve, reject) => {
    let resArr = [] // 存储处理结果的数组
    // 判断每一项是否处理完了
    let index = 0
    function processData (i, data) {
      resArr[i] = data
      index += 1
      if (index === lists.length) {
        // 处理异步,要使用计数器,不能使用resArr.length === lists.length
        resolve(resArr)
      }
    }

    for (let i = 0; i < lists.length; i++) {
      if (lists[i] instanceof MyPromise) {
        lists[i].then(data => {
          processData(i, data)
        }, err => {
          reject(err) // 只要有一个传入的promise没执行成功就走reject
          return
        })
      } else {
        processData(i, lists[i])
      }
    }
  })
}

// 两个方法赛跑,谁赢了就返回谁的状态
MyPromise.race = (lists) => {
  return new MyPromise((resolve, reject) => {
    for (let i = 0; i < lists.length; i++) {
      if (lists[i] instanceof MyPromise) {
        lists[i].then(data => {
          resolve(data) // 哪个先完成就返回哪一个的结果
          return
        }, err => {
          reject(err)
          return
        })
      } else {
        resolve(lists[i])
      }
    }
  })
}

// 所有方法执行完不管状态如何才返回
MyPromise.allSettled = (lists) => {
  return new MyPromise((resolve, reject) => {
    lists = Array.isArray(lists) ? lists : []
    let len = lists.length
    const argslen = len
    // 如果传入的是一个空数组,那么直接返回一个resolved的promise空数组对象
    if (len === 0) return resolve([])
    // 将传入的参数转化为数组,赋给args变量
    let args = Array.prototype.slice.call(lists)
    // 计算当前是否所有的promise执行完成,执行完毕则resolve
    const compute = () => {
      if (--len === 0) {
        resolve(args)
      }
    }
    function resolvePromise(index, value) {
      if (value instanceof MyPromise) {
        const then = value.then
        this.call(value, function(val) {
          args[index] = { status: FULFILLED, value: val }
          compute()
        }, function(err) {
          args[index] = { status: REJECTED, reason: e}
          compute()
        })
      } else {
        args[index] = { status: FULFILLED, value: value }
        compute()
      }
    }
    for(let i = 0; i < argslen; i++) {
      resolvePromise(i, args[i])
    }
  })
}