/*
|--------------------------------------------------------------------------
| Preloaded File - node ace make:preload rules/allowedExtensionsMimetypes
|--------------------------------------------------------------------------
|*/

import { FieldContext } from '@vinejs/vine/types';
import vine from '@vinejs/vine';
// import { VineString } from '@vinejs/vine';
import { VineMultipartFile, isBodyParserFile } from '#providers/vinejs_provider';
import type { MultipartFile } from '@adonisjs/core/bodyparser';
import MimeType from '#models/mime_type';

/**
 * Options accepted by the unique rule
 */
type Options = {
    // size: string | number;
    // extnames: string[];
    // clientNameSizeLimit?: number;
    allowedExtensions: string[];
    allowedMimeTypes?: string[];
};

// async function allowedMimetypeExtensions(file: VineMultipartFile | unknown, options: Options | unknown, field: FieldContext) {
async function allowedMimetypeExtensions(file: VineMultipartFile | unknown, options: Options, field: FieldContext) {
    if (!isBodyParserFile(file)) {
        return;
    }
    const validatedFile = file as MultipartFile;
    const mimeType = validatedFile?.headers['content-type']; // Get MIME type from the file
    const fileExtension = validatedFile?.extname?.toLocaleLowerCase() as string; // Get file extension from the file

    // validate if file extension is allowed in combination with mimetype
    let mimeRecord = await MimeType.query().select('file_extension').where('name', mimeType).andWhere('enabled', true).first();

    if (!mimeRecord) {
        mimeRecord = await MimeType.query()
            .select('file_extension')
            .whereRaw("? = ANY (string_to_array(alternate_mimetype, '|'))", [mimeType])
            .andWhere('enabled', true)
            .first();
    }

    if (!mimeRecord) {
        const allowedMimetypes = await MimeType.query().select('name').where('enabled', true);
        // Transform allowed MIME types to a concatenated string
        const allowedMimetypesString = allowedMimetypes.map((mime) => mime.name).join(', ');
        // throw new Error('Invalid MIME type');
        // Report error with the concatenated allowed MIME types
        field.report(
            `Invalid MIME type ${mimeType}. Allowed MIME types are: ${allowedMimetypesString}`,
            'allowedMimetypeExtensions',
            field,
        );
    } else {
        let allowedExtensions: string[] = [];
        if (options && options.allowedExtensions) {
            allowedExtensions = options.allowedExtensions;
        } else {
            allowedExtensions = mimeRecord.file_extension.split('|');
        }
        // Validate if the file's extension is in the allowed extensions
        if (!allowedExtensions.includes(fileExtension)) {
            //throw new Error(`File extension ${fileExtension} is not allowed for MIME type ${mimeType}`);
            field.report(
                `File extension ${fileExtension} is not allowed for MIME type ${mimeType}. Allowed extensions are: ${mimeRecord.file_extension}`,
                'allowedMimetypeExtensions',
                field,
            );
        }
        // if (validatedFile.clientName.length > options.clientNameSizeLimit) {

        //     field.report(`Filename length should be less or equal than ${options.clientNameSizeLimit} characters`, 'filenameLength', field);
        // }
    }
}

export const allowedMimetypeExtensionsRule = vine.createRule(allowedMimetypeExtensions);

declare module '#providers/vinejs_provider' {
    interface VineMultipartFile {
        allowedMimetypeExtensions(options?: Options): this;
    }
}

VineMultipartFile.macro('allowedMimetypeExtensions', function (this: VineMultipartFile, options: Options) {
    return this.use(allowedMimetypeExtensionsRule(options));
});
