import QuillDB from "../_/quilldb.js"
import fs from 'fs/promises'
import path from 'path'
import Title from "./model/Title.js"
import Member from './model/Member.js'
import Token from './model/Token.js'

export default class Database {
    nodes = [];
    types = [
        {
            validate: Title, 
            start: 0, 
            end: null, 
        },
        {
            validate: Member, 
            start: null, 
            end: null, 
        },
        {
            validate: Token, 
            start: null, 
            end: null, 
        },
    ]

    constructor() {
        this.loadData()
    }

    async loadData() {
        const dbData = await fs.readFile(path.join(process.cwd(), 'db/db.json'), 'utf8');
        let dbJson;
        try {
            dbJson = JSON.parse(dbData);
        } catch {
            dbJson = []
        }
        let nodes = dbJson["nodes"];
        this.validateNodes(nodes)
    }

    validateNodes(nodes) {
        nodes = Object.entries(nodes)

        let t = 0

        let currentType = () => {return this.types[t]}
        let nextType = () => {return this.types[t+1]}
        let selectNextType = () => {
            currentType().end = t
            t += 1;
            currentType().start = t
        }
        let lastNode = (i=null) => {
            if(i == null) throw new Error("must pass a param to lastNode()")
            return i+1 === nodes.length
        }

        for(let i=0; i<nodes.length; i++) {
            if(this.validateNode(currentType(), nodes[i])) {
                if(lastNode(i)) {
                    currentType().end = i
                    break;
                } else {
                    continue;
                }
            } else if(this.validateNode(nextType(), nodes[i])) {
                selectNextType()
                continue;
            } else {
                throw new Error("Nodes are out of order or corrupted!")
            }
        }
    }

    validateNode(type, node) {
        let [key, value] = node
        return type.validate(key, value)
    }

    get = {
        user: (id) => {
            return this.nodes[id]
        },
        userByEmail: (email) => {
            for (const id of this.labels["User"]) {
                const user = this.get.user(id);
                if (user.email === email) {
                    return  { id, ...user }
                }
            }
            return null;
        },
        token: (id) => {
            return this.nodes[`TOKEN-${id}`]
        }
    }

    add = {
        user: (node) => {
            let lastUser = {}

        }
    }

    submitNewUser(qrCodeID, userInfo) {
        let newUser = {
            labels: ["User"],
            ...userInfo
        }
        if(User(newUser))
            this.add.user(newUser)
    }

    generateUserID() {
        let id = this.labels["User"].length + 1;
        while (this.get.user(`user-${id}`)) {
            id++;
        }
        return `user-${id}`; // O(1) most of the time
    }
}