/**
 * Copyright (c) 2024-2026 Тарабанов Александр Викторович
 * All rights reserved.
 * 
 * This software is proprietary and confidential.
 * Unauthorized copying, modification, or distribution is prohibited.
 * 
 * For licensing inquiries: info@hb3-accelerator.com
 * Website: https://hb3-accelerator.com
 * GitHub: https://github.com/VC-HB3-Accelerator
 */

const { AppError, ErrorTypes } = require('../utils/error');
const logger = require('../utils/logger');
const { ERROR_CODES } = require('../utils/constants');

/**
 * Middleware для обработки ошибок
 */
const errorHandler = (err, req, res, next) => {
  // console.log('errorHandler called, arguments:', arguments);
  // console.log('typeof res:', typeof res, 'isFunction:', typeof res === 'function');
  // console.error('errorHandler: err =', err);
  // console.error('errorHandler: typeof err =', typeof err);
  // console.error('errorHandler: stack =', err && err.stack);
  // Логируем ошибку
  logger.error(`Error: ${err.message}`, {
    stack: err.stack,
    url: req.originalUrl,
    method: req.method,
    ip: req.ip,
    userId: req.session?.userId,
  });

  // Определяем тип ошибки
  let statusCode = 500;
  let errorCode = ERROR_CODES.INTERNAL_ERROR;
  let errorMessage = 'Внутренняя ошибка сервера';

  // Обрабатываем разные типы ошибок
  if (err.name === 'UnauthorizedError' || err.status === 401) {
    statusCode = 401;
    errorCode = ERROR_CODES.UNAUTHORIZED;
    errorMessage = 'Требуется аутентификация';
  } else if (err.status === 403) {
    statusCode = 403;
    errorCode = ERROR_CODES.FORBIDDEN;
    errorMessage = 'Доступ запрещен';
  } else if (err.status === 404) {
    statusCode = 404;
    errorCode = ERROR_CODES.NOT_FOUND;
    errorMessage = 'Ресурс не найден';
  } else if (err.status === 400) {
    statusCode = 400;
    errorCode = ERROR_CODES.BAD_REQUEST;
    errorMessage = err.message || 'Некорректный запрос';
  }

  // В режиме разработки возвращаем стек ошибки
  const devError = process.env.NODE_ENV === 'development' ? { stack: err.stack } : {};

  // Проверяем, что ответ еще не был отправлен и соединение не закрыто
  if (res.headersSent || res.destroyed) {
    console.error('[errorHandler] Ответ уже отправлен или соединение закрыто, пропускаем обработку ошибки');
    return;
  }

  // Для ошибок подключения к БД возвращаем понятное сообщение
  if (err.message && err.message.includes('timeout exceeded when trying to connect')) {
    errorMessage = 'Ошибка подключения к базе данных. Попробуйте позже.';
    statusCode = 503; // Service Unavailable
  }

  // Проверяем еще раз перед отправкой (может измениться состояние)
  if (res.headersSent || res.destroyed) {
    console.error('[errorHandler] Состояние изменилось, пропускаем отправку ответа');
    return;
  }

  // Отправляем ответ клиенту
  // Используем формат, совместимый с frontend (success: false, message: string)
  try {
    // Финальная проверка перед отправкой - состояние могло измениться
    if (res.headersSent || res.destroyed || res.finished || !res.writable) {
      console.error('[errorHandler] Финальная проверка: ответ уже отправлен, соединение закрыто или завершено');
      return;
    }
    
    // Проверяем writableEnded - новый флаг в Node.js
    if (res.writableEnded) {
      console.error('[errorHandler] Ответ уже завершен (writableEnded)');
      return;
    }
    
    res.status(statusCode).json({
      success: false,
      message: errorMessage,
      error: {
        code: errorCode,
        message: errorMessage,
        ...devError,
      },
    });
  } catch (sendErr) {
    // Если произошла ошибка при отправке (например, соединение закрыто), просто логируем
    // Игнорируем ошибки, связанные с уже отправленными заголовками или закрытым соединением
    if (sendErr.code !== 'ERR_HTTP_HEADERS_SENT' && 
        sendErr.code !== 'ECONNRESET' && 
        sendErr.code !== 'EPIPE' &&
        !sendErr.message?.includes('Cannot set headers after they are sent')) {
      console.error('[errorHandler] Ошибка при отправке ответа:', sendErr.message);
    }
  }
}

/**
 * Функция для создания ошибок с определенным статусом
 * @param {string} message - Сообщение об ошибке
 * @param {number} status - HTTP-статус ошибки
 * @returns {Error} - Объект ошибки
 */
function createError(message, status) {
  const error = new Error(message);
  error.status = status;
  return error;
}

module.exports = errorHandler;
// Если нужен createError для других файлов:
// module.exports.createError = createError;
