/**
 * Удобное хранение и освобождение временных ссылок
 * ВНИМАНИЕ: При очистке освобождаются все ссылки
 * 
 * @class RefManager
 * @property {Map<string, string>} refs - хранилище
 */
class RefManager {
    /**
     * @param {Map<string, string> | Object} [refs]
     */
    constructor (refs = null) {
        recovery((self) => {
            /** Инициализация хранилища */
            self.refs = new Map()

            if(refs) {
                if(Array.isArray(refs)) 
                    refs.forEach(ref => { self.save({ref}) });
                else {
                    /** Связки из аргумента refs */
                    const refs_entries = (refs instanceof Map)
                        ? refs.entries()
                        : (typeof refs === 'object' && refs !== null)
                        ? Object.entries(refs)
                        : (() => {throw new Error("Невалидный аргумент")})()
                    
                    /** Сохранение ссылок в хранилище */
                    Array.from(refs_entries).forEach(
                        ([key, ref]) => self.save({key, ref})
                    )
                }
            }
        }, (...e) => {
            console.log("Ошибка инициализии RefManager");
            e.forEach(er => {throw er});
        }) (this)
    }

    /**
     * Проверка ссылки
     * @static @method
     * @param {string} ref - ссылка
     * @returns {string}
     */
    static check = recovery(ref => {
        if(typeof ref !== 'string') 
            throw Error("Неизвестный объект в массиве строк")
        return ref
    }, (...e) => {
        console.log("Ошибка при проверке значения (RefManager.check)");
        e.forEach(er => {throw er});
    })

    /**
     * Сохранение сслыки
     * @method
     * @param {string} [key] - ключ
     * @param {string} ref - ссылка
     * @returns {{key: string, ref: string}} 
     */
    save = recovery(
        ({key = null, ref}) => {
            var now_key = key
                ? key 
                : (Date.now() + Math.random()).toString(36) 

            this.refs.set(RefManager.check(now_key), RefManager.check(ref))
            return {key: now_key, ref}
        },
        (...e) => {
            console.log("Ошибка при сохранении (save)");
            e.forEach(er => {throw er});
        }
    )

    /**
     * Получение ссылки по ключу
     * @method
     * @param {string} key - ключ
     * @returns {string}
     */
    get = recovery(
        key => {
            return this.refs.get(RefManager.check(key))
        },
        (...e) => {
            console.log("Ошибка при извлечении ссылки (get)");
            e.forEach(er => {throw er});
        }
    )

    /** 
     * Очищает все сохранённые ссылки и освобождает ресурсы
     * @method
     */
    clear = recovery(
        () => {
            Array.from(this.refs.values()).forEach(URL.revokeObjectURL);
            this.refs.clear()
        },
        (...e) => {
            console.log("Ошибка при очищении (clear)");
            e.forEach(er => {throw er});
        }
    )

    /** 
     * Возвращает сконвертированную в объект список 
     * @method
     * @returns {Object}
     */
    get_all = recovery(
        () => {
            return Object.fromEntries(this.refs)
        },
        (...e) => {
            console.log("Ошибка при конвертации и получени (get_all)");
            e.forEach(er => {throw er});
        }
    )

}