import { test } from 'node:test';
import assert from 'node:assert/strict';
import { ValidationError as SequelizeValidationError } from 'sequelize';
import { normalizeError } from '@/middlewares/error-handler';
import AppError from '@/shared/errors/app-error';
import ForbiddenError from '@/shared/errors/forbidden';
import ValidationError from '@/shared/errors/validation';
import UnauthorizedError from '@/shared/errors/unauthorized';
import NotFoundError from '@/shared/errors/not-found';

test('ForbiddenError → 403 with message and code', () => {
  const result = normalizeError(new ForbiddenError());
  assert.equal(result.status, 403);
  assert.equal(result.body.message, 'Forbidden');
  assert.equal(result.body.code, 'errors.forbidden.message');
  assert.equal(result.unexpected, false);
});

test('ValidationError → 400', () => {
  const result = normalizeError(new ValidationError());
  assert.equal(result.status, 400);
  assert.equal(result.unexpected, false);
});

test('UnauthorizedError → 401', () => {
  assert.equal(normalizeError(new UnauthorizedError()).status, 401);
});

test('NotFoundError → 404', () => {
  assert.equal(normalizeError(new NotFoundError()).status, 404);
});

test('AppError 5xx is marked unexpected (logged)', () => {
  const result = normalizeError(new AppError(503, 'down'));
  assert.equal(result.status, 503);
  assert.equal(result.unexpected, true);
});

test('error code (notification key) is preserved when provided', () => {
  const result = normalizeError(new ValidationError('auth.forbidden'));
  assert.equal(result.body.code, 'auth.forbidden');
});

test('Sequelize ValidationError → client 400 (not a 500)', () => {
  const result = normalizeError(
    new SequelizeValidationError('Validation error', []),
  );
  assert.equal(result.status, 400);
  assert.equal(result.body.code, 'errors.validation.message');
  assert.equal(result.unexpected, false);
});

test('native Error → generic 500, never leaks internals', () => {
  const result = normalizeError(new Error('connect ECONNREFUSED 5432'));
  assert.equal(result.status, 500);
  assert.notEqual(result.body.message, 'connect ECONNREFUSED 5432');
  assert.equal(result.body.code, 'errors.internal.message');
  assert.equal(result.unexpected, true);
});

test('non-Error thrown value → generic 500', () => {
  const result = normalizeError('boom');
  assert.equal(result.status, 500);
  assert.equal(result.unexpected, true);
});
