import {
  ExceptionFilter,
  Catch,
  ArgumentsHost,
  HttpException,
  HttpStatus,
  Logger,
} from '@nestjs/common';
import { Request, Response } from 'express';
import { I18nService, I18nContext } from 'nestjs-i18n';
import { ApiResponse, createErrorResponse } from '../types/api-response.type';

/**
 * Global exception filter that catches all exceptions
 * and returns a standardized ApiResponse with HTTP 200
 */
@Catch()
export class GlobalExceptionFilter implements ExceptionFilter {
  private readonly logger = new Logger(GlobalExceptionFilter.name);

  constructor(private readonly i18n?: I18nService) {}

  catch(exception: unknown, host: ArgumentsHost): void {
    const ctx = host.switchToHttp();
    const response = ctx.getResponse<Response>();
    const request = ctx.getRequest<Request>();

    // Determine status and message
    let status = HttpStatus.INTERNAL_SERVER_ERROR;
    let message = 'Internal server error';
    let errors: string[] = [];

    if (exception instanceof HttpException) {
      status = exception.getStatus();
      const exceptionResponse = exception.getResponse();

      if (typeof exceptionResponse === 'string') {
        message = exceptionResponse;
      } else if (typeof exceptionResponse === 'object') {
        const responseObj = exceptionResponse as Record<string, unknown>;
        message = (responseObj.message as string) || exception.message;

        // Handle validation errors (class-validator)
        if (Array.isArray(responseObj.message)) {
          errors = responseObj.message as string[];
          message = 'VALIDATION_FAILED';
        }
      }
    } else if (exception instanceof Error) {
      message = exception.message;
    }

    // Try to translate the message
    if (this.i18n) {
      try {
        const i18nContext = I18nContext.current();
        let lang = i18nContext?.lang;

        if (!lang) {
          const acceptLanguage = request.headers['accept-language'];
          const xLang = request.headers['x-lang'];

          if (xLang) {
            lang = Array.isArray(xLang) ? xLang[0] : xLang;
          } else if (acceptLanguage) {
            // Take first preferred language: "tr-TR,en;q=0.9" -> "tr"
            lang = acceptLanguage.split(',')[0].split(';')[0].split('-')[0];
          }
        }

        lang = lang || 'en';

        // Translate validation error specially
        if (message === 'VALIDATION_FAILED') {
          message = this.i18n.translate('errors.VALIDATION_FAILED', { lang });
        } else {
          // Try dynamic translation
          const translatedMessage = this.i18n.translate(`errors.${message}`, {
            lang,
          });
          // Only update if translation exists (key is different from result)
          if (translatedMessage !== `errors.${message}`) {
            message = translatedMessage as string;
          }
        }
      } catch {
        // Keep original message if translation fails
      }
    }

    // Log the error
    this.logger.error(
      `${request.method} ${request.url} - ${status} - ${message}`,
      exception instanceof Error ? exception.stack : undefined,
    );

    // Build response
    const isDevelopment = process.env.NODE_ENV === 'development';
    const errorResponse: ApiResponse<null> = createErrorResponse(
      message,
      status,
      errors,
      isDevelopment && exception instanceof Error ? exception.stack : undefined,
    );

    // Always return HTTP 200, actual status in body
    response.status(200).json(errorResponse);
  }
}
