const { NO_PARAMS } = require("../../utils/errorMessage");
const { STATUS_CODE } = require("../../utils/utility");
const routeHandler = require("../../utils/routeHandler");
const { isNull } = require("../../utils/validation");
const { sendAppError } = require("../../utils/appError");
const { Asset } = require("../../models");

const MAX_IMAGE_SIZE = 300 * 1024; // 300KB in bytes
const create = routeHandler(async (req, res, extras) => {
    const {
        type,
        owner_id,
    } = req.body;
    const { files } = req;
    const { user_id } = req.auth;

    const types = ["BANNER", "COMPANY_LOGO"];

    const paramNames = ["Files", "Type"];
    const { hasNull, missingParams } = isNull([files, type]);

    if (hasNull || !types.includes(type)) {
        const missingParamNames = missingParams.map(index => paramNames[index]);
        if (!types.includes(type)) {
            return sendAppError(extras, `Invalid type '${type}'. Expected types are: ${types.join(', ')}`, STATUS_CODE.BAD_REQUEST);
        }
        return sendAppError(extras, `${missingParamNames.join(', ')} ${missingParamNames.length > 1 ? 'are' : 'is'} required`, STATUS_CODE.BAD_REQUEST);
    }

    try {
        if (type == "COMPANY_LOGO") {
            const asset = await Asset.findOne({ where: { type } });
            if (asset) {
                return sendAppError(extras, 'Company logo already exists', STATUS_CODE.BAD_REQUEST);
            }
            if (files?.length > 1) {
                return sendAppError(extras, 'Company logo image must be more than one', STATUS_CODE.BAD_REQUEST);
            }
        }

        for (let file of files) {
            if (file.size > MAX_IMAGE_SIZE) {
                return sendAppError(extras, `File ${file.originalname} exceeds the size limit of 300KB`, STATUS_CODE.BAD_REQUEST);
            }
        }

        const assetData = [];
        files.forEach(file => {
            assetData.push({
                type: type.replace(/ /g, "_").toUpperCase(),
                owner_id: '',
                name: file.originalname,
                data: file.buffer,
                mimetype: file.mimetype,
                created_by: user_id,
            });
        });

        const assets = await Asset.bulkCreate(assetData, { transaction: extras.transaction });

        await extras.transaction.commit();
        return res.sendRes(assets, {
            message: 'Assets saved successfully',
            status: STATUS_CODE.CREATED,
        });
    } catch (error) {
        await extras.transaction.rollback();
        return sendAppError(extras, error.message, STATUS_CODE.INTERNAL_SERVER_ERROR);
    }
});

const getAll = routeHandler(async (req, res, extras) => {
    const { type } = req.query;

    const filter = {};
    if (type) {
        filter["type"] = type;
    }

    const assets = await Asset.findAll({
        order: [['created_at', 'DESC'],],
        ...req.paginate,
        where: filter,
    });
    return res.sendRes(assets, {
        message: "Assets loaded successfully",
        ...req.meta,
        total: await Asset.count(),
        status: STATUS_CODE.OK,
    });
}, false);

const getById = routeHandler(async (req, res, extras) => {
    const { asset_id } = req.params;
    const asset = await Asset.findOne({ where: { asset_id } });

    if (!asset) {
        return sendAppError(extras, 'Asset not found', STATUS_CODE.NOT_FOUND);
    }
    return res.sendRes(asset, { message: 'Asset loaded successfully', status: STATUS_CODE.OK });
}, false);

const updateById = routeHandler(async (req, res, extras) => {
    const { asset_id } = req.params;
    const {
        type,
        owner_id,
    } = req.body;
    const { file } = req;
    const { user_id } = req.auth;

    const types = ["BANNER"];

    const paramNames = ["Files", "Type"];
    const { hasNull, missingParams } = isNull([file, type]);

    if (hasNull || !types.includes(type)) {
        const missingParamNames = missingParams.map(index => paramNames[index]);
        if (!types.includes(type)) {
            return sendAppError(extras, `Invalid type '${type}'. Expected types are: ${types.join(', ')}`, STATUS_CODE.BAD_REQUEST);
        }
        return sendAppError(extras, `${missingParamNames.join(', ')} ${missingParamNames.length > 1 ? 'are' : 'is'} required`, STATUS_CODE.BAD_REQUEST);
    }
    try {
        const asset = await Asset.findOne({ where: { asset_id } });
        if (!asset) {
            return sendAppError(extras, 'Asset not found', STATUS_CODE.NOT_FOUND);
        }

        if (file.size > MAX_IMAGE_SIZE) {
            return sendAppError(extras, `File ${file.originalname} exceeds the size limit of 300KB`, STATUS_CODE.BAD_REQUEST);
        }

        await asset.update({
            type,
            owner_id,
            name: file.originalname,
            data: file.buffer,
            mimetype: file.mimetype,
            updated_by: user_id,
        }, { transaction: extras.transaction });

        await extras.transaction.commit();
        return res.sendRes(asset, { message: 'Asset updated successfully', status: STATUS_CODE.OK, });
    } catch (error) {
        await extras.transaction.rollback();
        return sendAppError(extras, error.message, STATUS_CODE.INTERNAL_SERVER_ERROR);
    }
});

const deleteById = routeHandler(async (req, res, extras) => {
    const { asset_id } = req.params;
    const { user_id } = req.auth;

    const asset = await Asset.findOne({ where: { asset_id } });

    if (!asset) {
        return sendAppError(extras, 'Asset not found', STATUS_CODE.NOT_FOUND);
    }

    await asset.update({
        deleted_by: user_id,
    }, { transaction: extras.transaction });

    await asset.destroy({ transaction: extras.transaction });

    await extras.transaction.commit();
    return res.sendRes(null, { message: 'Asset deleted successfully', status: STATUS_CODE.OK });
});

module.exports = {
    create,
    getAll,
    getById,
    updateById,
    deleteById,
};
