const resolvePromise = (promise2,x,resolve,reject) => {
	if(promise2 === x){
		return reject(new TypeError('Chaining cycle detected for promise #<Promise>'))
	}
	let called;
	if(typeof x === 'function' || (typeof x === 'object' && typeof x !==null)){
		try{
			let then = x.then
			if(typeof then === 'function'){
				then.call(x,y=>{
					if(called) return
          			called = true;
          			resolvePromise(promise2,y,resolve,reject)
				},r=>{
					if(called) return
          			called = true;
          			reject(r)
				})
			}else{
				resolve(x)
			}
		}catch(e){
			if(called) return
          	called = true;
			reject(e)
		}
	}else{
		resolve(x)
	}
}
const PENDING = 'PEDNING'
const FULFILLED = 'FULFILLED'
const REJECTED = 'REJECTED'
class Promise{
	constructor(executor){
		this.status = PENDING
		this.value = undefined
		this.reason = undefined
		this.onResolvedCallbacks = []
		this.onRejectedCallbacks = []
		let resove = (value)=>{
			if(this.status === PENDING){
				this.status = FULFILLED
				this.value = value 
				this.onResolvedCallbacks.forEach(fn=>fn())
			}
		}
		let reject = (reason)=>{
			if(this.status === PENDING){
				this.status = REJECTED
				this.reason = reason
				this.onRejectedCallbacks.forEach(fn=>fn())
			}
		}
		try {
			executor(resolve,reject)
		}catch(e){
			reject(e)
		}
	}
	then(onFulfilled,onRejected){
		onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : v => v;
		onRejected = typeof onRejected === 'function' ? onRejected : e => {throw e}
		let promise2 = new Promise((resolve,reject)=>{
			if(this.status === FUlFILLED){
				setTimeout(()=>{
					try{
						let x = onFulfilled(this.value)
						resolvePromise(promise2,x,resolve,reject)
					}catch(e){
						reject(e)
					}
				})
			}
			if(this.status === REJECTED){
				setTimeout(()=>{
					try{
						let x = onRejected(this.reason)
						resolvePromise(promise2,x,resolve,reject)
					}catch(e){
						reject(e)
					}
				})
			}
			if(this.status === PENDING){
				this.onResolvedCallbacks.push(()=>{
					setTimeout(()=>{
						try{
							let x = onFulfilled(this.value)
							resolvePromise(promise2,x,resolve,reject)
						}catch(e){
							reject(e)
						}
					})
				})
				this.onRejectedCallbacks.push(()=>{
					setTimeout(()=>{
						try{
							let x = onRejected(this.reason)
							resolvePromise(promise2,x,resolve,reject)
						}catch(e){
							reject(e)
						}
					})
				})
			}
		})
		return promise2
	}
}