import * as fs from "node:fs";
import AdmZip from "adm-zip";
import { queueLogger } from "../../logger.js";
import { createTempDir } from "../../../misc/create-temp.js";
import { downloadUrl } from "../../../misc/download-url.js";
import { DriveFiles, Emojis } from "../../../models/index.js";
import { addFile } from "../../../services/drive/add-file.js";
import { genId } from "../../../misc/gen-id.js";
import { db } from "../../../db/postgre.js";
import probeImageSize from "probe-image-size";
import * as path from "path";
const logger = queueLogger.createSubLogger("import-custom-emojis");
// TODO: 名前衝突時の動作を選べるようにする
export async function importCustomEmojis(job) {
    logger.info("Importing custom emojis ...");
    const file = await DriveFiles.findOneBy({
        id: job.data.fileId
    });
    if (file == null) {
        return "skip: File not found";
    }
    const [tempPath, cleanup] = await createTempDir();
    logger.info(`Temp dir is ${tempPath}`);
    const destPath = `${tempPath}/emojis.zip`;
    try {
        fs.writeFileSync(destPath, "", "binary");
        await downloadUrl(file.url, destPath);
    } catch (e) {
        // TODO: 何度か再試行
        if (e instanceof Error || typeof e === "string") {
            logger.error(e);
        }
        throw e;
    }
    const outputPath = `${tempPath}/emojis`;
    const unzipStream = fs.createReadStream(destPath);
    const zip = new AdmZip(destPath);
    logger.succ(`Unzipping to ${outputPath}`);
    await new Promise((resolve, reject)=>{
        zip.extractAllToAsync(outputPath, true, false, async (error)=>{
            if (error) reject(error);
            if (fs.existsSync(`${outputPath}/meta.json`)) {
                logger.info("starting emoji import with metadata");
                const metaRaw = fs.readFileSync(`${outputPath}/meta.json`, "utf-8");
                const meta = JSON.parse(metaRaw);
                for (const record of meta.emojis){
                    if (!record.downloaded) continue;
                    const emojiInfo = record.emoji;
                    const emojiPath = `${outputPath}/${record.fileName}`;
                    await Emojis.delete({
                        name: emojiInfo.name
                    });
                    const driveFile = await addFile({
                        user: null,
                        path: emojiPath,
                        name: record.fileName,
                        force: true
                    });
                    const file = fs.createReadStream(emojiPath);
                    const size = await probeImageSize(file);
                    file.destroy();
                    await Emojis.insert({
                        id: genId(),
                        updatedAt: new Date(),
                        name: emojiInfo.name,
                        category: emojiInfo.category,
                        host: null,
                        aliases: emojiInfo.aliases,
                        originalUrl: driveFile.url,
                        publicUrl: driveFile.webpublicUrl ?? driveFile.url,
                        type: driveFile.webpublicType ?? driveFile.type,
                        license: emojiInfo.license,
                        width: size.width || null,
                        height: size.height || null
                    }).then((x)=>Emojis.findOneByOrFail(x.identifiers[0]));
                }
            } else {
                logger.info("starting emoji import without metadata");
                // Since we lack metadata, we import into a randomized category name instead
                let categoryName = genId();
                let containedEmojis = fs.readdirSync(outputPath);
                // Filter out accidental JSON files
                containedEmojis = containedEmojis.filter((emoji)=>!emoji.match(/\.(json)$/i));
                for (const emojiFilename of containedEmojis){
                    // strip extension and get filename to use as name
                    const name = path.basename(emojiFilename, path.extname(emojiFilename));
                    const emojiPath = `${outputPath}/${emojiFilename}`;
                    logger.info(`importing ${name}`);
                    await Emojis.delete({
                        name: name
                    });
                    const driveFile = await addFile({
                        user: null,
                        path: emojiPath,
                        name: path.basename(emojiFilename),
                        force: true
                    });
                    const file = fs.createReadStream(emojiPath);
                    const size = await probeImageSize(file);
                    file.destroy();
                    logger.info(`emoji size: ${size.width}x${size.height}`);
                    await Emojis.insert({
                        id: genId(),
                        updatedAt: new Date(),
                        name: name,
                        category: categoryName,
                        host: null,
                        aliases: [],
                        originalUrl: driveFile.url,
                        publicUrl: driveFile.webpublicUrl ?? driveFile.url,
                        type: driveFile.webpublicType ?? driveFile.type,
                        license: null,
                        width: size.width || null,
                        height: size.height || null
                    }).then((x)=>Emojis.findOneByOrFail(x.identifiers[0]));
                }
            }
            await db.queryResultCache.remove([
                "meta_emojis"
            ]);
            cleanup();
            logger.succ("Imported");
            resolve(undefined);
        });
    });
    return "Success";
}
