"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
    return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.IpfsFactory = void 0;
const ipfs_http_client_1 = require("ipfs-http-client");
const buffer_1 = require("buffer");
const debug_1 = require("../utils/debug");
const web3_storage_1 = require("web3.storage");
const it_to_stream_1 = __importDefault(require("it-to-stream"));
const uuid_1 = require("uuid");
class IpfsFactory {
    constructor() {
    }
    static async getInstance(options) {
        if (!IpfsFactory.instance) {
            IpfsFactory.instance = new IpfsFactory();
            IpfsFactory.ipfs = await (0, ipfs_http_client_1.create)({
                host: options.useLocalIpfs === true ? 'localhost' : 'ipfsnode'
            });
            return IpfsFactory.instance;
        }
        return IpfsFactory.instance;
    }
    async generateCidFromData(data, buffer, domain, options) {
        if (options.useLocalIpfs) {
            (0, debug_1.devLog)('use local ipfs');
            return this.generateCidFromLocalIpfsNode(buffer);
        }
        else {
            (0, debug_1.devLog)('use web3 ipfs');
            return this.generateCidFromWeb3IpfsNode(buffer, domain, data, options);
        }
    }
    async generateDataFromCid(cid, ipfsOptions, options) {
        if ((await this.checkIfWeHaveCidInWeb3(cid, options)) === false)
            return null;
        (0, debug_1.devLog)('____start fetch cid content with ipfs_______');
        const results = await IpfsFactory.ipfs.cat(cid, {
            offset: (ipfsOptions && ipfsOptions.json === false && ipfsOptions.start) ? ipfsOptions.start : undefined,
            length: (ipfsOptions && ipfsOptions.json === false && ipfsOptions.end) ? ipfsOptions.end : undefined,
            timeout: 1000 * 60 * 5,
        });
        (0, debug_1.devLog)('____cid content found with ipfs______');
        if (ipfsOptions?.json === true) {
            let data = '';
            for await (const chunk of results) {
                data += chunk.toString();
            }
            return JSON.parse(data);
        }
        if (ipfsOptions?.json === false) {
            if (ipfsOptions?.stream === true) {
                return it_to_stream_1.default.readable(results);
            }
            else {
                let buffer = buffer_1.Buffer.alloc(0);
                for await (const chunk of results) {
                    buffer = buffer_1.Buffer.concat([buffer, chunk]);
                }
                return buffer;
            }
        }
    }
    async generateCidFromLocalIpfsNode(buffer) {
        const r = await IpfsFactory.ipfs.add(buffer, {
            wrapWithDirectory: false
        });
        (0, debug_1.devLog)('done save file to local ipfs with cid', r.cid.toString());
        return {
            cid: r.cid.toString(),
            size: r.size
        };
    }
    async generateCidFromWeb3IpfsNode(buffer, domain, data, options) {
        const web3Storage = new web3_storage_1.Web3Storage({
            token: options.web3Token
        });
        const file = new web3_storage_1.File([buffer], `${domain}_${data._id}`);
        const r = await web3Storage.put([file], {
            wrapWithDirectory: false,
            name: `${domain}_${(0, uuid_1.v4)()}`,
        });
        return {
            cid: r,
            size: 0
        };
    }
    async checkIfWeHaveCidInWeb3(cid, options) {
        if (options.useLocalIpfs === true) {
            return true;
        }
        else {
            const web3Storage = new web3_storage_1.Web3Storage({
                token: options.web3Token
            });
            const data = await web3Storage.get(cid);
            return !!(data.ok && await data.files);
        }
    }
}
exports.IpfsFactory = IpfsFactory;
