// @ts-nocheck
import type { ApplicationService } from '@adonisjs/core/types';
import { validator } from '@adonisjs/validator';
import { Request } from '@adonisjs/core/http';
import { RequestNegotiator } from '@adonisjs/validator/types';
// import { Rule } from '@adonisjs/validator/types';
// import { VanillaErrorReporter } from '@adonisjs/validator/build/src/error_reporter/index.js';
import db from '@adonisjs/lucid/services/db';

type Options = {
    table: string;
    column: string;
    whereNot?: { id: any };
};
declare module '@adonisjs/validator/types' {
    export interface Rules {
        translatedLanguage(mainLanguageField: string, typeField: string): Rule;
        uniqueArray(field: string): Rule;
        unique(args: Options): Rule;
    }
}

export default class ValidatorProvider {
    constructor(protected app: ApplicationService) {}

    /**
     * Register bindings to the container
     */
    register() {}

    /**
     * The container bindings have booted
     */
    async boot() {
        // Add custom validation rules

        // this.app.container.resolving('validator', (validator) => {
        //     validator.rule('foo', () => {})
        // })

        // validator.configure({
        //     reporter: validator.reporters.vanilla,
        // });
        await this.configureValidator();

        validator.rule('uniqueArray', (dataArray, [field], { pointer, arrayExpressionPointer, errorReporter }) => {
            const array = dataArray; //validator.helpers.getFieldValue(data, field, tip);

            if (!Array.isArray(array)) {
                throw new Error(`The ${pointer} must be an array.`);
            }

            const uniqueValues = new Set();
            for (let i = 0; i < array.length; i++) {
                const item = array[i];
                const attributeValue = item[field]; // Extract the attribute value for uniqueness check

                if (uniqueValues.has(attributeValue)) {
                    // throw new Error(`The ${field} array contains duplicate values for the ${field} attribute.`)
                    errorReporter.report(
                        pointer,
                        'uniqueArray', // Keep an eye on this
                        `The ${pointer} array contains duplicate values for the ${field} attribute.`,
                        arrayExpressionPointer,
                        { field, array: pointer },
                    );
                    return;
                }

                uniqueValues.add(attributeValue);
            }
        });

        validator.rule(
            'unique',
            async (data, [{ table, column, whereNot }], { pointer, errorReporter, arrayExpressionPointer, field }) => {
                const value = data; // get(data, column);'admin'
                if (!value) {
                    return;
                }

                let ignoreId: string | null = whereNot?.id;
                // let ignoreId: string | null = null;
                // const fields = args[1].split('/');
                // const table = args[0];
                // if (args[2]) {
                //     ignoreId = args[2];
                // }
                const columnName = column || field;
                const builder = db.from(table).select(columnName).where(columnName, '=', value);
                if (ignoreId) {
                    builder.whereNot('id', '=', ignoreId);
                }
                const row = await builder.first();

                if (row) {
                    // throw message;
                    errorReporter.report(pointer, 'unique', 'Unique validation failed', arrayExpressionPointer, { field });
                }
            },
            () => ({
                async: true,
            }),
        );

        validator.rule(
            'translatedLanguage',
            (value, [mainLanguageField, typeField], { root, tip, pointer, arrayExpressionPointer, errorReporter }) => {
                if (typeof value !== 'string') {
                    return;
                }
                // const fieldValue = validator. getValue(data, field)
                // this should return the "category_id" value present in "root", but i got undefined
                const mainLanguage = validator.helpers.getFieldValue(mainLanguageField, root, tip);
                const type = validator.helpers.getFieldValue(typeField, root, tip); //'type' = 'Translated'

                if (type && type === 'Translated') {
                    if (value === mainLanguage) {
                        errorReporter.report(
                            pointer,
                            'translatedLanguage', // Keep an eye on this
                            'translatedLanguage validation failed',
                            arrayExpressionPointer,
                            { mainLanguage },
                        );
                    }
                }

                // if (value !== string.camelCase(value)) {
                //     options.errorReporter.report(
                //         options.pointer,
                //         'camelCase',
                //         'camelCase validation failed',
                //         options.arrayExpressionPointer
                //     );
                // }
            },
        );

        validator.rule('fileExtension', async (value, [extensions], { pointer, arrayExpressionPointer, errorReporter }) => {
            const allowedExtensions = extensions.map((ext: string) => ext.toLowerCase());
            const uploadedFile = value;

            if (!uploadedFile) {
                return;
            }

            const extension = uploadedFile.extname.toLowerCase().replace('.', '');

            if (!allowedExtensions.includes(extension)) {
                errorReporter.report(
                    pointer,
                    'fileExtension',
                    'Invalid file extension. Only {{ extensions }} files are allowed.',
                    arrayExpressionPointer,
                );
            }
        });

        // validator.rule(
        //     'clamavScan',
        //     (value, [field], { root, tip, pointer, arrayExpressionPointer, errorReporter }) => {
        //         if (typeof value !== 'object') {
        //             return;
        //         }
        //         const uploadedFile = validator.helpers.getFieldValue(field, root, tip);
        //     // return rules.file({}, [
        //     //     async (file) => {
        //     //         const clamdhost = process.env['CLAMD_HOST'] ?? '127.0.0.1';
        //     //         const clamdport = Number(process.env['CLAMD_PORT']) ?? '3310';
        //     //         try {
        //     //             var isInfected = await scanFileForViruses(file.tmpPath, clamdhost, clamdport);
        //     //         } catch (error) {
        //     //             throw new Error(`${pointer}: ${error.message}`);
        //     //         }
        //     //     },
        //     // ]);
        // });

        // async function scanFileForViruses(filePath, host, port): Promise<boolean> {
        //     // const clamscan = await (new ClamScan().init());
        //     const opts: ClamScan.Options = {
        //         preference: 'clamdscan',
        //         clamdscan: {
        //             active: true,
        //             host,
        //             port,
        //             multiscan: true,
        //         },
        //     };
        //     const clamscan = await new ClamScan().init(opts);

        //     return new Promise((resolve, reject) => {
        //         clamscan.isInfected(filePath, (err, file, isInfected: boolean) => {
        //             if (err) {
        //                 reject(err);
        //             } else if (isInfected) {
        //                 reject(new Error(`File ${file} is infected!`));
        //             } else {
        //                 resolve(isInfected);
        //             }
        //         });
        //     });
        // }
    }

    /**
     * Configure the validator
     */
    async configureValidator() {
        // const config = await this.app.container.make('config');
        validator.configure({
            reporter: validator.reporters.vanilla,
            // @ts-ignore
            negotiator: (callback: RequestNegotiator) => {
                this.getRequestReporter = callback;
            },
        });
    }
    getRequestReporter(request: Request) {
        // if (request.ajax()) {
        //     return ErrorReporters.ApiErrorReporter;
        // }
        switch (request.accepts(['html', 'application/vnd.api+json', 'json'])) {
            case 'html':
            case null:
                return validator.reporters.vanilla;
            case 'json':
                return validator.reporters.api;
            case 'application/vnd.api+json':
                return validator.reporters.jsonapi;
        }
    }

    /**
     * The application has been booted
     */
    async start() {}

    /**
     * The process has been started
     */
    async ready() {}

    /**
     * Preparing to shutdown the app
     */
    async shutdown() {}
}
