import express from 'express';
import assert from 'node:assert/strict';
import { describe, it } from 'node:test';
import onError from '../../src/middlewares/errors.js';
import { HttpError, RateLimitExceededError } from '../../src/httpErrors.js';

describe('errors middleware', () => {
  it('headers sent, do nothing', () => {
    let actualStatus: number | undefined;
    let actualJson: Record<string, unknown> | undefined;

    const response = {
      headersSent: true,
      status: (code: number) => {
        actualStatus = code;

        return {
          json: (json: Record<string, unknown>) => {
            actualJson = json;
          },
        };
      },
      locals: { logger: { error: () => undefined } },
    } as unknown as express.Response;

    onError(new Error(), {} as express.Request, response, () => {});

    assert.strictEqual(actualStatus, undefined);
    assert.strictEqual(actualJson, undefined);
  });

  it('handles httpError', () => {
    let actualStatus: number | undefined;
    let actualJson: Record<string, unknown> | undefined;

    const response = {
      headersSent: false,
      status: (code: number) => {
        actualStatus = code;

        return {
          json: (json: Record<string, unknown>) => {
            actualJson = json;
          },
        };
      },
      locals: { logger: { error: () => undefined } },
    } as unknown as express.Response;
    onError(new HttpError('httpError', 429), {} as express.Request, response, () => {});

    assert.strictEqual(actualStatus, 429);
    assert.deepEqual(actualJson, { code: '429', message: 'httpError' });
  });

  it('handles retry-after header', () => {
    let actualStatus: number | undefined;
    let actualJson: Record<string, unknown> | undefined;

    const response = {
      headersSent: false,
      status: (code: number) => {
        actualStatus = code;

        return {
          json: (json: Record<string, unknown>) => {
            actualJson = json;
          },
        };
      },
      locals: { logger: { error: () => undefined } },
      setHeader: (name: string, value: string) => {
        assert.strictEqual(name, 'Retry-After');
        assert.strictEqual(value, '1234');
      },
    } as unknown as express.Response;
    onError(new RateLimitExceededError('httpError', { retryAfter: 1234 }), {} as express.Request, response, () => {});

    assert.strictEqual(actualStatus, 429);
    assert.deepEqual(actualJson, { code: '429', message: 'httpError' });
  });

  it('handles other error', () => {
    let actualStatus: number | undefined;
    let actualJson: Record<string, unknown> | undefined;

    const response = {
      headersSent: false,
      status: (code: number) => {
        actualStatus = code;

        return {
          json: (json: Record<string, unknown>) => {
            actualJson = json;
          },
        };
      },
      locals: { logger: { error: () => undefined } },
    } as unknown as express.Response;
    onError(new Error('error'), {} as express.Request, response, () => {});

    assert.strictEqual(actualStatus, 500);
    assert.strictEqual(actualJson?.code, '500');
    assert.deepEqual(actualJson?.originalError, { code: 'Error', message: 'error' });
  });
});
