/*
 * Copyright (c) 2022.
 * Author Peter Placzek (tada5hi)
 * For the full copyright and license information,
 * view the LICENSE file that was distributed with this source code.
 */

import path from "path";
import {getWritableDirPath} from "../../config/paths";
import * as fs from "fs";
import sharp, {Sharp} from "sharp";
import {v4} from "uuid";
import {ImageCropCoordinates, ImageCropResizeConfig} from "@chamesu/common/domains/image/crop";
import {QueueMessage} from "../../modules/message-queue/type";

/**
 * Resize image as step in the resolve chain of the image command.
 *
 * @param message
 */
export async function resizeImage(message: QueueMessage) {
    const srcFilePath : string = path.resolve(getWritableDirPath(), message.data.srcFilePath);
    const cropCoordinates : ImageCropCoordinates = message.data.cropCoordinates;
    const cropResizeConfig : ImageCropResizeConfig = message.data.cropResizeConfig;

    message.resultSizes = await doResizeImage(srcFilePath, cropCoordinates, cropResizeConfig);

    return message;
}

/**
 * Resize image (srcFilePath) and place resized variants of image
 * to same directory.
 *
 * @param srcFilePath
 * @param cropCoordinates
 * @param cropResizeConfig
 */
async function doResizeImage(srcFilePath: string, cropCoordinates: any, cropResizeConfig: ImageCropResizeConfig) : Promise<ImageResizeResponse[]> {
    const buffer: Buffer = fs.readFileSync(srcFilePath);

    /**
     * sharp(buffer).png
     */
    const instance: Sharp = sharp(buffer)
        .extract({
            width: cropCoordinates.width,
            height: cropCoordinates.height,
            left: cropCoordinates.left,
            top: cropCoordinates.top
        });

    const promises: Promise<ImageResizeResponse>[] = [];
    const destinationPath = path.dirname(srcFilePath);

    const ratio : string = (cropCoordinates.width / cropCoordinates.height).toFixed(1);

    for (let i = 0; i < cropResizeConfig.sizes.length; i++) {
        const fileName: string = v4() + '.png';
        const sizePath: string = path.resolve(destinationPath, fileName);
        const height: number = Number((cropResizeConfig.sizes[i].width / Number(ratio)).toFixed());

        promises.push(new Promise<ImageResizeResponse>(((resolve, reject) => {
            instance
                .clone()
                .resize({
                    width: cropResizeConfig.sizes[i].width
                })
                .toFile(sizePath, ((err: Error) => {
                    if (err) reject(err);

                    resolve({
                        dimensions: {
                            width: cropResizeConfig.sizes[i].width,
                            height: height
                        },
                        file: fileName,
                        name: cropResizeConfig.sizes[i].name
                    });
                }));
        })));
    }

    return Promise.all(promises);
}

export type ImageResizeResponse = {
    dimensions: {
        width: number,
        height: number
    },
    file: string,
    name: string
}
