import yaml from 'js-yaml';

/**
 * Yaml访问器
 */

export default class Yaml {

    #config: Record<string, any> = {};
    indent = 2;

    constructor(content: string | Record<string, any>, indent?: number) {
        if (content) {
            if (typeof content === 'string') {
                this.#config = yaml.load(content) || {};
            } else if (typeof content === 'object') {
                Object.assign(this.#config, content);
            }
        }
        if (indent && indent > 0) {
            this.indent = indent;
        }
    }

    /**
     * 获取值
     * @param {[String]} keys 键清单
     * @return {*} 值
     */
    get(keys: string[] = []): string | Record<string, any> | undefined {
        let value: string | Record<string, any> = this.#config;
        for (let k of keys) {
            if (typeof value === 'object') {
                value = value[k];
            } else {
                return undefined;
            }
        }
        return value;
    }

    /**
     * 设置值
     * @param {[String]} keys 键清单
     * @param {*} value 值
     */
    set(keys: string[], value: any): void {
        let parent = this.#getParentNode(keys);
        parent[keys[keys.length - 1]] = value;
    }

    #getParentNode(keys: string[]): Record<string, any> {
        // 确保路径上的所有父对象都存在
        let parent = this.#config;
        for (let i = 0; i < keys.length - 1; i++) {
            const key = keys[i];
            if (parent[key] === undefined || parent[key] === null) {
                parent[key] = {};
            }
            parent = parent[key];
        }
        return parent;
    }

    /**
     * 仅当值不存在时设置
     * @param {[String]} keys 键清单
     * @param {*} value 值
     * @returns {boolean} 是否设置成功
     */
    setIfAbsent(keys: string[], value: any): boolean {
        let parent = this.#getParentNode(keys);
        const lastKey = keys[keys.length - 1];
        if (parent[lastKey] !== undefined && parent[lastKey] !== null) {
            return false;
        }
        parent[lastKey] = value;
        return true;
    }

    /**
     * 删除指定键路径上的值
     * - 验证所有key必须是字符串
     * - 递归删除并在父节点为空对象时一并清理
     */
    remove(keys: string[]) {
        // 如果只有一个键，直接从根配置中删除
        if (keys.length === 1) {
            if (keys[0] in this.#config) {
                delete this.#config[keys[0]];
                return true;
            }
            return false;
        }

        // 递归删除并检查父节点
        const removeRecursive = (obj: Record<string, any>, keyPath: string[], index: number): boolean => {
            // 已到达倒数第二层
            if (index === keyPath.length - 1) {
                const lastKey = keyPath[index];
                if (lastKey in obj) {
                    delete obj[lastKey];
                    return true;
                }
                return false;
            }

            const currentKey = keyPath[index];
            if (!(currentKey in obj) || typeof obj[currentKey] !== 'object' || Array.isArray(obj[currentKey])) {
                return false; // 路径不存在或不是对象
            }

            const result = removeRecursive(obj[currentKey], keyPath, index + 1);

            // 如果删除成功且当前节点为空对象，则删除当前节点
            if (result && Object.keys(obj[currentKey]).length === 0) {
                delete obj[currentKey];
            }

            return result;
        };

        return removeRecursive(this.#config, keys, 0);
    }

    isEmpty(): boolean {
        return Object.keys(this.#config).length === 0;
    }

    toString() {
        if (this.isEmpty()) {
            return '';
        }
        return yaml.dump(this.#config, {
            indent: this.indent,
            lineWidth: -1,
            quotingType: '"',
            forceQuotes: false,
        });
    }

}
