const fs = require('fs-extra');
const path = require('path');
const gm = require('gm');

module.exports = Self => {
    require('../methods/image/download')(Self);
    require('../methods/image/upload')(Self);
    require('../methods/image/scrub')(Self);

    Self.resize = async function({collectionName, srcFile, fileName, entityId}) {
        const models = Self.app.models;

        const collection = await models.ImageCollection.findOne(
            {
                fields: [
                    'id',
                    'maxWidth',
                    'maxHeight',
                    'model',
                    'property',
                ],
                where: {name: collectionName},
                include: {
                    relation: 'sizes',
                    scope: {
                        fields: ['width', 'height', 'crop'],
                    },
                },
            }
        );

        // Insert image row
        const imageName = path.parse(fileName).name;
        await models.Image.upsertWithWhere(
            {
                name: imageName,
                collectionFk: collectionName
            },
            {
                name: imageName,
                collectionFk: collectionName,
                updated: Date.vnNow() / 1000,
            }
        );

        // Update entity image file name
        const model = models[collection.model];
        if (!model) throw new Error('No matching model found');

        const entity = await model.findById(entityId);
        if (entity) {
            await entity.updateAttribute(
                collection.property,
                imageName
            );
        }

        // Resize
        const container = await models.ImageContainer.container(
            collectionName
        );
        const rootPath = container.client.root;
        const collectionDir = path.join(rootPath, collectionName);

        // To max size
        const {maxWidth, maxHeight} = collection;
        const fullSizePath = path.join(collectionDir, 'full');
        const toFullSizePath = `${fullSizePath}/${fileName}`;

        await fs.mkdir(fullSizePath, {recursive: true});
        await new Promise((resolve, reject) => {
            gm(srcFile)
                .resize(maxWidth, maxHeight, '>')
                .setFormat('png')
                .quality(100)
                .write(toFullSizePath, function(err) {
                    if (err) reject(err);
                    if (!err) resolve();
                });
        });

        // To collection sizes
        for (const size of collection.sizes()) {
            const {width, height} = size;

            const sizePath = path.join(collectionDir, `${width}x${height}`);
            const toSizePath = `${sizePath}/${fileName}`;

            await fs.mkdir(sizePath, {recursive: true});
            await new Promise((resolve, reject) => {
                const gmInstance = gm(srcFile);

                if (size.crop) {
                    gmInstance
                        .resize(width, height, '^')
                        .gravity('Center')
                        .crop(width, height);
                }

                if (!size.crop) gmInstance.resize(width, height, '>');

                gmInstance
                    .setFormat('png')
                    .quality(100)
                    .write(toSizePath, function(err) {
                        if (err) reject(err);
                        if (!err) resolve();
                    });
            });
        }
    };
};