import { ID, Item, MerkleTreeHashNode, MerkleTreeLayerNodeList, MerkleTreeLeafNodeList, Transaction, createFHash, getAtomicItemHash } from "../../internals";
import crypto from 'crypto'

export class MerkleTreeLeafNode {
     /**
     * @param {ID} id
     * @param {Array<{
     *   struct: Item,
     *   hash?: string
     * }>} targets
     * @param {{
     *   leafNodeList: MerkleTreeLeafNodeList,
     *   layerNodeList: MerkleTreeLayerNodeList,
     *   merkleTreeRoot: MerkleTreeHashNode | null | undefined,
     * }} store
     */
    constructor(id, targets, store){
        /**
         * leafNode所对应的client
         */
        this.client = id.client
        /**
         * leafNode搜索对应的clock
         */
        this.clock = id.clock
        /**
         * targets首先需要按照hash进行排序，从小到大排序
         * @type {Array<{
         *   struct: Item,
         *   hash?: string
         * }>}
         */
        this.targets = targets.sort((tar1, tar2) => this.getTargetHash(tar1).localeCompare(this.getTargetHash(tar2)))
        /**
         * 所对应的byzantine client store
         */
        this.store = store
        /**
         * @type {MerkleTreeHashNode | MerkleTreeLeafNode | null | undefined}
         */
        this.parent = null
        /**
         * 所绑定的hash
         * @type {string}
         */
        this.hash = ''
        this.updateHash()
        /**
         * @type {string}
         */
        this._fhash = ''
    }

    get fHash(){
        if(this._fhash) return this._fhash
        const fhash = createFHash(this, this.store)
        this._fhash = fhash
        return fhash
    }

    /**
     * 
     * @param {{
     *   struct: Item,
     *   hash?: string
     * }} target 
     */
    addTarget(target){
        const hash = target.hash ? target.hash : this.getTargetHash(target)
        const index = this.targets.findIndex(target => (target.hash ? target.hash : this.getTargetHash(target)).localeCompare(hash) <= 0)
        if(index > -1){
            this.targets.splice(index, 0, target)
        } else {
            this.targets.push(target)
        }
        this.updateHash()
    }

    /**
     * 获得某一个target的hash
     * @param {{
     *  struct: Item,
     *  hash?: string
     * }} target
     * @returns {string}
     */
    getTargetHash(target){
        if(target.hash) return target.hash 
        const offset = this.clock - target.struct.id.clock
        const hash = getAtomicItemHash(target.struct, offset)
        target.hash = hash
        return hash
    }

    /**
     * 更新hash
     */
    updateHash(){
        // 构建hash
        const hashStr = this.targets.map(target => target.hash).join('')
        this.hash = crypto.createHash("sha256").update(hashStr).digest('base64')
        setTimeout(() => {
            if(this.parent && this.parent instanceof MerkleTreeHashNode){
                this.parent.computeHash()
            }
        }, 0);
        return this.hash
    }
}