"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
    return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.FileImageStorageService = void 0;
const axios_1 = __importDefault(require("axios"));
const promises_1 = __importDefault(require("fs/promises"));
const path_1 = __importDefault(require("path"));
const MIME_TO_EXTENSION = {
    'image/png': 'png',
    'image/jpeg': 'jpg',
    'image/jpg': 'jpg',
    'image/svg+xml': 'svg',
    'image/gif': 'gif',
    'image/webp': 'webp',
    'image/avif': 'avif',
    'image/x-icon': 'ico',
    'image/vnd.microsoft-icon': 'ico',
};
const EXTENSION_TO_MIME = {
    png: 'image/png',
    jpg: 'image/jpeg',
    jpeg: 'image/jpeg',
    svg: 'image/svg+xml',
    gif: 'image/gif',
    webp: 'image/webp',
    avif: 'image/avif',
    ico: 'image/x-icon',
    bin: 'application/octet-stream',
};
const FOLDER_NAME = {
    network: 'networks',
    token: 'tokens',
};
const isExternalUrl = (url) => {
    const lower = url.toLowerCase();
    return lower.startsWith('http://') || lower.startsWith('https://');
};
const isNotFoundError = (error) => {
    if (!axios_1.default.isAxiosError(error)) {
        return false;
    }
    const axiosError = error;
    return axiosError.response?.status === 404;
};
class FileImageStorageService {
    publicBaseUrl;
    imagesDir;
    thumbnailResolver;
    constructor(publicBaseUrl, imagesDir, thumbnailResolver) {
        this.publicBaseUrl = publicBaseUrl;
        this.imagesDir = imagesDir;
        this.thumbnailResolver = thumbnailResolver;
    }
    async downloadAndStore(type, id, url, metadata) {
        if (!isExternalUrl(url)) {
            return url;
        }
        try {
            return await this.downloadImage(type, id, url);
        }
        catch (error) {
            if (!isNotFoundError(error) || !this.thumbnailResolver || !metadata) {
                throw error;
            }
        }
        const fallbackUrl = await this.thumbnailResolver.resolve(type, metadata);
        if (!fallbackUrl) {
            return null;
        }
        return this.downloadImage(type, id, fallbackUrl);
    }
    async readImage(type, id) {
        const folder = path_1.default.resolve(this.imagesDir, FOLDER_NAME[type]);
        try {
            await promises_1.default.access(folder);
        }
        catch {
            return null;
        }
        const files = await promises_1.default.readdir(folder);
        const filename = files.find((file) => file.startsWith(`${id}.`));
        if (!filename) {
            return null;
        }
        const ext = filename.split('.').pop()?.toLowerCase() ?? 'bin';
        const contentType = EXTENSION_TO_MIME[ext] ?? 'application/octet-stream';
        const buffer = await promises_1.default.readFile(path_1.default.join(folder, filename));
        return { buffer, contentType };
    }
    async downloadImage(type, id, url) {
        const folder = path_1.default.resolve(this.imagesDir, FOLDER_NAME[type]);
        await promises_1.default.mkdir(folder, { recursive: true });
        const response = await axios_1.default.get(url, {
            responseType: 'arraybuffer',
            timeout: 30000,
            maxRedirects: 5,
            validateStatus: (status) => status < 400,
        });
        const contentType = response.headers['content-type']?.toString() ?? 'application/octet-stream';
        const extension = MIME_TO_EXTENSION[contentType.split(';')[0].trim().toLowerCase()] ?? 'bin';
        const filename = `${id}.${extension}`;
        const filePath = path_1.default.join(folder, filename);
        await promises_1.default.writeFile(filePath, Buffer.from(response.data));
        const publicUrl = `${this.publicBaseUrl}/images/${FOLDER_NAME[type]}/${filename}`;
        return publicUrl;
    }
}
exports.FileImageStorageService = FileImageStorageService;
//# sourceMappingURL=file-image-storage.service.js.map