const corsMiddleware = require('../../../src/api/middlewares/corsMiddleware');

describe('CORS Middleware', () => {
  let req, res, next;

  beforeEach(() => {
    req = {
      headers: {},
      method: 'GET',
    };
    res = {
      setHeader: jest.fn(),
      status: jest.fn().mockReturnThis(),
      end: jest.fn(),
    };
    next = jest.fn();
  });

  describe('Allowed origins', () => {
    test('should allow requests from http://localhost:3001', () => {
      req.headers.origin = 'http://localhost:3001';

      corsMiddleware(req, res, next);

      expect(res.setHeader).toHaveBeenCalledWith('Access-Control-Allow-Origin', 'http://localhost:3001');
      expect(res.setHeader).toHaveBeenCalledWith('Access-Control-Allow-Credentials', 'true');
      expect(next).toHaveBeenCalled();
    });

    test('should allow requests from http://localhost:3000', () => {
      req.headers.origin = 'http://localhost:3000';

      corsMiddleware(req, res, next);

      expect(res.setHeader).toHaveBeenCalledWith('Access-Control-Allow-Origin', 'http://localhost:3000');
      expect(res.setHeader).toHaveBeenCalledWith('Access-Control-Allow-Credentials', 'true');
      expect(next).toHaveBeenCalled();
    });

    test('should allow requests from https://myapp.com', () => {
      req.headers.origin = 'https://myapp.com';

      corsMiddleware(req, res, next);

      expect(res.setHeader).toHaveBeenCalledWith('Access-Control-Allow-Origin', 'https://myapp.com');
      expect(res.setHeader).toHaveBeenCalledWith('Access-Control-Allow-Credentials', 'true');
      expect(next).toHaveBeenCalled();
    });
  });

  describe('Disallowed origins', () => {
    test('should reject requests from unknown origins', () => {
      req.headers.origin = 'http://malicious-site.com';

      corsMiddleware(req, res, next);

      expect(res.status).toHaveBeenCalledWith(403);
      expect(res.end).toHaveBeenCalledWith('CORS policy: Origin not allowed');
      expect(next).not.toHaveBeenCalled();
    });

    test('should reject requests from http://evil.com', () => {
      req.headers.origin = 'http://evil.com';

      corsMiddleware(req, res, next);

      expect(res.status).toHaveBeenCalledWith(403);
      expect(res.end).toHaveBeenCalledWith('CORS policy: Origin not allowed');
      expect(next).not.toHaveBeenCalled();
    });
  });

  describe('Preflight requests (OPTIONS)', () => {
    beforeEach(() => {
      req.method = 'OPTIONS';
    });

    test('should handle OPTIONS request from allowed origin', () => {
      req.headers.origin = 'http://localhost:3001';

      corsMiddleware(req, res, next);

      expect(res.setHeader).toHaveBeenCalledWith('Access-Control-Allow-Origin', 'http://localhost:3001');
      expect(res.setHeader).toHaveBeenCalledWith('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE, OPTIONS');
      expect(res.setHeader).toHaveBeenCalledWith('Access-Control-Allow-Headers', 'Content-Type, Authorization');
      expect(res.setHeader).toHaveBeenCalledWith('Access-Control-Allow-Credentials', 'true');
      expect(res.status).toHaveBeenCalledWith(204);
      expect(res.end).toHaveBeenCalled();
      expect(next).not.toHaveBeenCalled();
    });

    test('should reject OPTIONS request from disallowed origin', () => {
      req.headers.origin = 'http://hackersite.com';

      corsMiddleware(req, res, next);

      expect(res.status).toHaveBeenCalledWith(403);
      expect(res.end).toHaveBeenCalledWith('CORS policy: Origin not allowed');
      expect(next).not.toHaveBeenCalled();
    });
  });

  describe('No origin header', () => {
    test('should allow requests without origin header (same-origin)', () => {
      delete req.headers.origin;

      corsMiddleware(req, res, next);

      expect(next).toHaveBeenCalled();
    });
  });

  describe('Headers configuration', () => {
    test('should set correct CORS headers for allowed origin', () => {
      req.headers.origin = 'http://localhost:3000';

      corsMiddleware(req, res, next);

      expect(res.setHeader).toHaveBeenCalledWith('Access-Control-Allow-Origin', 'http://localhost:3000');
      expect(res.setHeader).toHaveBeenCalledWith('Access-Control-Allow-Credentials', 'true');
    });

    test('should set method headers for OPTIONS request', () => {
      req.headers.origin = 'http://localhost:3000';
      req.method = 'OPTIONS';

      corsMiddleware(req, res, next);

      expect(res.setHeader).toHaveBeenCalledWith('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE, OPTIONS');
      expect(res.setHeader).toHaveBeenCalledWith('Access-Control-Allow-Headers', 'Content-Type, Authorization');
    });
  });

  describe('Real-world scenarios', () => {
    test('should handle POST request from allowed frontend', () => {
      req.headers.origin = 'http://localhost:3001';
      req.method = 'POST';

      corsMiddleware(req, res, next);

      expect(res.setHeader).toHaveBeenCalledWith('Access-Control-Allow-Origin', 'http://localhost:3001');
      expect(res.setHeader).toHaveBeenCalledWith('Access-Control-Allow-Credentials', 'true');
      expect(next).toHaveBeenCalled();
    });

    test('should reject DELETE request from disallowed origin', () => {
      req.headers.origin = 'http://unauthorized.com';
      req.method = 'DELETE';

      corsMiddleware(req, res, next);

      expect(res.status).toHaveBeenCalledWith(403);
      expect(next).not.toHaveBeenCalled();
    });
  });
});
