import { MerkleTreeLeafNode } from "./LeafNode"
import crypto from 'crypto'

/**
 * 
 * @param {MerkleTreeHashNode | MerkleTreeLeafNode | undefined | null} leftChild 
 * @param {MerkleTreeHashNode | MerkleTreeLeafNode | undefined | null} rightChild 
 * @returns 
 */
const createHash = (leftChild, rightChild = undefined) => {
    let hashStr = ''
    if(leftChild){
        hashStr += leftChild.hash
    }
    if(rightChild){
        hashStr += rightChild.hash
    }
    return crypto.createHash("sha256").update(hashStr).digest('base64')
}

export class MerkleTreeHashNode {
    constructor(){
        /**
         * @type {MerkleTreeHashNode | MerkleTreeLeafNode | null | undefined}
         */
        this._left = null
        /**
         * @type {MerkleTreeHashNode | MerkleTreeLeafNode | null | undefined}
         */
        this._right = null
        /**
         * @type {MerkleTreeHashNode | null | undefined}
         */
        this.parent = null
        /**
         * @type {string | null | undefined}
         */
        this.hash = null
    }

    /**
     * @param {MerkleTreeHashNode | MerkleTreeLeafNode | null | undefined} newLeft
     */
    set left(newLeft){
        this._left = newLeft
        if(newLeft){
            newLeft.parent = this
        }
        this.computeHash()
    }

    get left(){
        return this._left
    }

    /**
     * @param {MerkleTreeHashNode | MerkleTreeLeafNode | null | undefined} newRight
     */
    set right(newRight){
        this._right = newRight
        if(newRight){
            newRight.parent = this
        }
        this.computeHash()
    }

    get right(){
        return this._right
    }

    computeHash(){
        this.hash = createHash(this._left, this._right)
        this.parent?.computeHash()
    }
}