import { Request, Response, NextFunction } from 'express';
import { ValidateError } from 'tsoa';
import { logger } from '../config/logger';

export function errorHandler(
    err: any,
    req: Request,
    res: Response,
    next: NextFunction
): Response | void {
    // TSOA Validation Error
    if (err instanceof ValidateError) {
        logger.warn('Validation error', {
            fields: err.fields,
            path: req.path
        });

        return res.status(422).json({
            error: {
                code: 'VALIDATION_ERROR',
                message: 'Validation failed',
                details: err.fields
            }
        });
    }

    // JWT Errors
    if (err.name === 'JsonWebTokenError') {
        return res.status(401).json({
            error: {
                code: 'UNAUTHORIZED',
                message: 'Invalid token'
            }
        });
    }

    if (err.name === 'TokenExpiredError') {
        return res.status(401).json({
            error: {
                code: 'TOKEN_EXPIRED',
                message: 'Token has expired'
            }
        });
    }

    // Prisma Errors
    if (err.code === 'P2002') {
        return res.status(409).json({
            error: {
                code: 'DUPLICATE_ENTRY',
                message: 'A record with this value already exists',
                details: err.meta
            }
        });
    }

    if (err.code === 'P2025') {
        return res.status(404).json({
            error: {
                code: 'NOT_FOUND',
                message: 'Record not found'
            }
        });
    }

    // Custom Application Errors
    if (err.statusCode) {
        return res.status(err.statusCode).json({
            error: {
                code: err.code || 'APPLICATION_ERROR',
                message: err.message,
                details: err.details
            }
        });
    }

    // Log unexpected errors
    logger.error('Unexpected error', {
        error: err.message,
        stack: err.stack,
        path: req.path,
        method: req.method
    });

    // Default error
    return res.status(500).json({
        error: {
            code: 'INTERNAL_ERROR',
            message: 'An unexpected error occurred'
        }
    });
}

export class ApplicationError extends Error {
    constructor(
        public statusCode: number,
        public code: string,
        message: string,
        public details?: any
    ) {
        super(message);
        this.name = 'ApplicationError';
    }
}

export class ValidationError extends ApplicationError {
    constructor(message: string, details?: any) {
        super(400, 'VALIDATION_ERROR', message, details);
        this.name = 'ValidationError';
    }
}

export class UnauthorizedError extends ApplicationError {
    constructor(message = 'Unauthorized') {
        super(401, 'UNAUTHORIZED', message);
        this.name = 'UnauthorizedError';
    }
}

export class ForbiddenError extends ApplicationError {
    constructor(message = 'Forbidden') {
        super(403, 'FORBIDDEN', message);
        this.name = 'ForbiddenError';
    }
}

export class NotFoundError extends ApplicationError {
    constructor(message = 'Resource not found') {
        super(404, 'NOT_FOUND', message);
        this.name = 'NotFoundError';
    }
}
