"use strict";
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
    var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
    if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
    else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
    return c > 3 && r && Object.defineProperty(target, key, r), r;
};
Object.defineProperty(exports, "__esModule", { value: true });
const common_1 = require("@nestjs/common");
const typeorm_1 = require("typeorm");
const zod_1 = require("zod");
const __1 = require("..");
let GlobalExceptionFilter = class GlobalExceptionFilter {
    catch(exception, host) {
        const ctx = host.switchToHttp();
        const response = ctx.getResponse();
        let status = common_1.HttpStatus.INTERNAL_SERVER_ERROR;
        let errorDetails = 'An unexpected error occurred';
        let errorMessage = null;
        __1.logger.error(`Error eee: ${exception}`);
        const normalizeMessage = (v) => {
            try {
                if (typeof v === 'string')
                    return v.replace(/\s+/g, ' ').trim();
                if (v === undefined || v === null)
                    return '';
                if (v.driverError?.sqlMessage)
                    return String(v.driverError.sqlMessage);
                if (v.sqlMessage)
                    return String(v.sqlMessage);
                if (v.message && typeof v.message === 'string')
                    return v.message.replace(/\s+/g, ' ').trim();
                if (v.message && Array.isArray(v.message))
                    return v.message.join(', ');
                return JSON.stringify(v);
            }
            catch {
                return String(v);
            }
        };
        const extractUniqueConstraintMessage = (v) => {
            const normalized = normalizeMessage(v);
            if (!normalized)
                return null;
            const directMatch = normalized.match(/Unique constraint failed on the constraint:\s*`[^`]+`/i);
            if (directMatch?.[0])
                return directMatch[0];
            const fieldsMatch = normalized.match(/Unique constraint failed on the fields:\s*\(([^)]+)\)/i);
            if (fieldsMatch?.[1]) {
                const field = String(fieldsMatch[1])
                    .replace(/["'`\s]/g, '')
                    .split(',')[0];
                return field
                    ? `Unique constraint failed on the constraint: \`${field}_key\``
                    : 'Unique constraint failed on the constraint';
            }
            return null;
        };
        const isZodTree = (v) => v && typeof v === 'object' && 'errors' in v && 'properties' in v;
        const collectZodTreeErrors = (node, prefix = '') => {
            if (!node || typeof node !== 'object')
                return [];
            const messages = [];
            const errors = Array.isArray(node.errors) ? node.errors : [];
            for (const message of errors) {
                messages.push(prefix ? `${prefix} : ${message}` : String(message));
            }
            const properties = node.properties ?? {};
            for (const key of Object.keys(properties)) {
                const nextPrefix = prefix ? `${prefix}.${key}` : key;
                messages.push(...collectZodTreeErrors(properties[key], nextPrefix));
            }
            return messages;
        };
        const groupZodTreeErrors = (node, prefix = '') => {
            if (!node || typeof node !== 'object')
                return {};
            const grouped = {};
            const errors = Array.isArray(node.errors) ? node.errors : [];
            for (const message of errors) {
                if (prefix) {
                    if (!grouped[prefix]) {
                        grouped[prefix] = [];
                    }
                    grouped[prefix].push(String(message));
                }
            }
            const properties = node.properties ?? {};
            for (const key of Object.keys(properties)) {
                const nextPrefix = prefix ? `${prefix}.${key}` : key;
                const nestedGrouped = groupZodTreeErrors(properties[key], nextPrefix);
                Object.assign(grouped, nestedGrouped);
            }
            return grouped;
        };
        if (exception instanceof common_1.HttpException) {
            status = exception.getStatus();
            const res = exception.getResponse();
            const raw = typeof res === 'string' ? res : (res?.message ?? res);
            if (res?.message && isZodTree(res.message)) {
                const messageObj = res.message;
                const groupedErrors = groupZodTreeErrors(messageObj);
                errorDetails = {
                    errors: groupedErrors,
                };
                const detailMessages = [];
                Object.entries(groupedErrors).forEach(([field, messages]) => {
                    messages.forEach((msg) => {
                        detailMessages.push(msg);
                    });
                });
                errorMessage = detailMessages.join(', ');
            }
            else if (isZodTree(raw)) {
                const groupedErrors = groupZodTreeErrors(raw);
                errorDetails = {
                    errors: groupedErrors,
                };
                const detailMessages = [];
                Object.entries(groupedErrors).forEach(([field, messages]) => {
                    messages.forEach((msg) => {
                        detailMessages.push(msg);
                    });
                });
                errorMessage = detailMessages.join(', ');
            }
            else {
                const uniqueConstraintMessage = extractUniqueConstraintMessage(raw);
                if (uniqueConstraintMessage) {
                    status = common_1.HttpStatus.BAD_REQUEST;
                    errorDetails = uniqueConstraintMessage;
                    errorMessage = null;
                }
                else {
                    errorDetails = normalizeMessage(raw) || errorDetails;
                }
            }
        }
        else if (exception instanceof zod_1.ZodError) {
            status = common_1.HttpStatus.BAD_REQUEST;
            const issueList = exception.issues.map((issue) => ({
                path: issue.path.join('.'),
                message: issue.message,
            }));
            const groupedErrors = issueList.reduce((acc, issue) => {
                if (!acc[issue.path]) {
                    acc[issue.path] = [];
                }
                acc[issue.path].push(issue.message);
                return acc;
            }, {});
            errorDetails = { errors: groupedErrors };
            errorMessage = issueList
                .map((issue) => `${issue.path} : ${issue.message}`)
                .join(', ');
        }
        else if (exception && typeof exception === 'object') {
            const ex = exception;
            if (ex instanceof typeorm_1.QueryFailedError &&
                (ex.driverError?.code === 'ER_DUP_ENTRY' ||
                    ex.driverError?.errno === 1062)) {
                status = common_1.HttpStatus.BAD_REQUEST;
                const duplicateMessage = ex.driverError?.sqlMessage;
                errorDetails = duplicateMessage
                    ? duplicateMessage
                    : 'Unique constraint failed on the constraint';
                errorMessage = null;
            }
            else {
                const uniqueConstraintMessage = extractUniqueConstraintMessage(ex);
                if (uniqueConstraintMessage) {
                    status = common_1.HttpStatus.BAD_REQUEST;
                    errorDetails = uniqueConstraintMessage;
                    errorMessage = null;
                }
                else {
                    const extractRaw = () => {
                        if (!ex)
                            return undefined;
                        if (ex.driverError?.sqlMessage)
                            return ex.driverError.sqlMessage;
                        if (ex.sqlMessage)
                            return ex.sqlMessage;
                        if (typeof ex.message === 'string')
                            return ex.message;
                        if (ex.message && typeof ex.message === 'object') {
                            return ex.message.sqlMessage ?? ex.message.message ?? ex.message;
                        }
                        return ex;
                    };
                    const stringify = (v) => {
                        try {
                            if (typeof v === 'string')
                                return v;
                            if (v === undefined || v === null)
                                return '';
                            if (typeof v === 'object')
                                return JSON.stringify(v);
                            return String(v);
                        }
                        catch {
                            return String(v);
                        }
                    };
                    const raw = extractRaw();
                    errorDetails = stringify(raw) || 'An unexpected error occurred';
                    errorDetails = errorDetails.replace(/\s+/g, ' ').trim();
                    if (ex?.driverError?.sqlMessage ||
                        ex?.sqlMessage ||
                        /duplicate entry/i.test(errorDetails)) {
                        status = common_1.HttpStatus.BAD_REQUEST;
                    }
                }
            }
        }
        __1.logger.error(`Error message: ${normalizeMessage(errorDetails)}`);
        response.status(status).json({
            status,
            message: errorMessage,
            details: errorDetails,
            data: null,
        });
    }
};
GlobalExceptionFilter = __decorate([
    (0, common_1.Catch)()
], GlobalExceptionFilter);
exports.default = GlobalExceptionFilter;
//# sourceMappingURL=globalExceptionFilter.config.js.map