import { QORT_DECIMALS, TX_TYPES } from '../../constants'
import nacl from '../../deps/nacl-fast'
import Base58 from '../../deps/Base58'
import utils from '../../deps/utils'

export default class ChatBase {
	static get utils() {
		return utils
	}

	static get nacl() {
		return nacl
	}

	static get Base58() {
		return Base58
	}

	constructor() {
		this.fee = 0
		this.groupID = 0
		this.tests = [
			() => {
				if (!(this._type >= 1 && this._type in TX_TYPES)) {
					return 'Invalid type: ' + this.type
				}
				return true
			},
			() => {
				if (this._fee < 0) {
					return 'Invalid fee: ' + this._fee / QORT_DECIMALS
				}
				return true
			},
			() => {
				if (this._groupID < 0 || !Number.isInteger(this._groupID)) {
					return 'Invalid groupID: ' + this._groupID
				}
				return true
			},
			() => {
				if (!(new Date(this._timestamp)).getTime() > 0) {
					return 'Invalid timestamp: ' + this._timestamp
				}
				return true
			},
			() => {
				if (!(this._lastReference instanceof Uint8Array && this._lastReference.byteLength == 64)) {
					return 'Invalid last reference: ' + this._lastReference
				}
				return true
			},
			() => {
				if (!(this._keyPair)) {
					return 'keyPair must be specified'
				}
				if (!(this._keyPair.publicKey instanceof Uint8Array && this._keyPair.publicKey.byteLength === 32)) {
					return 'Invalid publicKey'
				}
				if (!(this._keyPair.privateKey instanceof Uint8Array && this._keyPair.privateKey.byteLength === 64)) {
					return 'Invalid privateKey'
				}
				return true
			}
		]
	}

	set keyPair(keyPair) {
		this._keyPair = keyPair
	}

	set type(type) {
		this.typeText = TX_TYPES[type]
		this._type = type
		this._typeBytes = this.constructor.utils.int32ToBytes(this._type)
	}

	set groupID(groupID) {
		this._groupID = groupID
		this._groupIDBytes = this.constructor.utils.int32ToBytes(this._groupID)
	}

	set timestamp(timestamp) {
		this._timestamp = timestamp
		this._timestampBytes = this.constructor.utils.int64ToBytes(this._timestamp)
	}

	set fee(fee) {
		this._fee = fee * QORT_DECIMALS
		this._feeBytes = this.constructor.utils.int64ToBytes(this._fee)
	}

	set lastReference(lastReference) {
		this._lastReference = lastReference instanceof Uint8Array ? lastReference : this.constructor.Base58.decode(lastReference)
	}

	get params() {
		return [
			this._typeBytes,
			this._timestampBytes,
			this._groupIDBytes,
			this._lastReference,
			this._keyPair.publicKey
		]
	}

	get chatBytes() {
		const isValid = this.validParams()
		if (!isValid.valid) {
			throw new Error(isValid.message)
		}

		let result = new Uint8Array()

		this.params.forEach(item => {
			result = this.constructor.utils.appendBuffer(result, item)
		})

		this._chatBytes = result

		return this._chatBytes
	}

	validParams() {
		let finalResult = {
			valid: true
		}

		this.tests.some(test => {
			const result = test()
			if (result !== true) {
				finalResult = {
					valid: false,
					message: result
				}
				return true
			}
		})

		return finalResult
	}

}