import {StateBranchNode} from "./StateBranchNode";
import {TestableNodeWithBranchAndFlow} from "./TestableNode";
import {TreeNode} from "./TreeNode";
import {generateIdForType, throwError} from "./NodeHelpers";
import {TestableCompositeData, TestableData, TestablePartial} from "./store";
import {TestableFormat, Testables} from "./testables";
import {FlowDataWithoutPosition} from "./FlowDataCreator";
import {BeforeAddingToGroveHook} from "./Grove";
import {TestableCompositeNode} from "./TestableCompositeNode";

export type NestedTestableNodeData = {
    /**
     * An id is required!
     */
    id: string,
    type: TestableCompositeData["type"],
    mode: TestableCompositeData["mode"],
    children: NestedTestableNodeData[] | TestableData[]
} | TestableData | TestablePartial

export class InMemoryTestableNode implements TestableNodeWithBranchAndFlow, BeforeAddingToGroveHook {
    // @ts-ignore
    private treeNode: TreeNode;
    // @ts-ignore
    public branch: StateBranchNode;

    constructor(
        private readonly nestedTestableNodeData: NestedTestableNodeData,
        private readonly testables: Testables,
        /**
         * Only if the testable is a partial (this is required if so)
         */
        private readonly partialParentId?: string,
    ) {}

    /**
     * This is where we'll add the testable data to the state
     * and create a real testable node
     * and set that to the treeNode and branch
     */
    beforeAddingToGrove(): void {
        // if this only has id and options, its a partial so add it to the partials
        if ('type' in this.nestedTestableNodeData) {
            // add testable data to the state
            this.testables.addTestables([this.nestedTestableNodeData], TestableFormat.Nested)
        } else {
            // this is a partial
            this.testables.addTestablePartials([this.nestedTestableNodeData], this.partialParentId!)
        }
        // now let's make the swap to the real testable node

        // for now let's create a testable composite node but this may vary based on the type of the testable
        const testableNode = new TestableCompositeNode(this.testables, this.nestedTestableNodeData.id)
        // set the testable node to the treeNode
        this.treeNode?.setTestableNode?.(testableNode)
        // for now i don't know if this object will persist in memory or not, it could be the source of a memory leak?
    }

    getId(): string {
        return this.nestedTestableNodeData.id;
    }

    createFlowData(): FlowDataWithoutPosition {
        throw new Error("Method not implemented. The swap to the real testable node should have been done by now");
    }
    exportToState(): string {
        throw new Error("Method not implemented. The swap to the real testable node should have been done by now");
    }

    setTreeNode(treeNode: TreeNode): void {
        this.treeNode = treeNode;
    }
    getTreeNode(): TreeNode {
        return this.treeNode;
    }
    setBranch(branch: StateBranchNode) {
        this.branch = branch
    }
}