/**
 * Unit Tests für hostGate Middleware
 * Testet Host-basierte Zugriffskontrolle
 */

// Setup ENV VOR dem Require
process.env.ENABLE_HOST_RESTRICTION = 'true';
process.env.PUBLIC_HOST = 'public.example.com';
process.env.INTERNAL_HOST = 'internal.example.com';
process.env.NODE_ENV = 'development';

let hostGate;

// Helper to create mock request with headers
const createMockRequest = (hostname, path = '/') => {
    return {
        path,
        get: (headerName) => {
            if (headerName.toLowerCase() === 'x-forwarded-host') {
                return hostname;
            }
            if (headerName.toLowerCase() === 'host') {
                return hostname;
            }
            return null;
        }
    };
};

describe('Host Gate Middleware', () => {
    let req, res, next;
    let originalEnv;

    beforeAll(() => {
        // Sichere Original-Env
        originalEnv = { ...process.env };
        
        // Lade Modul NACH ENV setup
        hostGate = require('../../../src/middlewares/hostGate');
    });

    beforeEach(() => {
        // Mock response object
        res = {
            status: jest.fn().mockReturnThis(),
            json: jest.fn()
        };

        // Mock next function
        next = jest.fn();
        
        // Reset req for each test
        req = null;

        // Setup Environment
        process.env.ENABLE_HOST_RESTRICTION = 'true';
        process.env.PUBLIC_HOST = 'public.example.com';
        process.env.INTERNAL_HOST = 'internal.example.com';
        process.env.NODE_ENV = 'development'; // NOT 'test' to enable restrictions
    });

    afterEach(() => {
        jest.clearAllMocks();
    });

    afterAll(() => {
        // Restore Original-Env
        process.env = originalEnv;
    });

    describe('Host Detection', () => {
        test('should detect public host from X-Forwarded-Host header', () => {
            req = createMockRequest('public.example.com');
            hostGate(req, res, next);

            expect(req.isPublicHost).toBe(true);
            expect(req.isInternalHost).toBe(false);
            expect(req.requestSource).toBe('public');
        });

        test('should detect internal host from X-Forwarded-Host header', () => {
            req = createMockRequest('internal.example.com');
            hostGate(req, res, next);

            expect(req.isPublicHost).toBe(false);
            expect(req.isInternalHost).toBe(true);
            expect(req.requestSource).toBe('internal');
        });

        test('should fallback to Host header if X-Forwarded-Host not present', () => {
            req = createMockRequest('public.example.com');
            hostGate(req, res, next);

            expect(req.isPublicHost).toBe(true);
        });

        test('should handle localhost as internal host', () => {
            req = createMockRequest('localhost:3000');
            hostGate(req, res, next);

            expect(req.isInternalHost).toBe(true);
            expect(req.isPublicHost).toBe(false);
        });

        test('should strip port from hostname', () => {
            req = createMockRequest('public.example.com:8080');
            hostGate(req, res, next);

            expect(req.isPublicHost).toBe(true);
        });
    });

    describe('Route Protection', () => {
        test('should block admin routes on public host', () => {
            req = createMockRequest('public.example.com', '/api/admin/deletion-log');
            hostGate(req, res, next);

            expect(res.status).toHaveBeenCalledWith(403);
            expect(res.json).toHaveBeenCalledWith({
                error: 'Not available on public host',
                message: 'This endpoint is only available on the internal network'
            });
            expect(next).not.toHaveBeenCalled();
        });

        test('should block groups routes on public host', () => {
            req = createMockRequest('public.example.com', '/api/groups');
            hostGate(req, res, next);

            expect(res.status).toHaveBeenCalledWith(403);
        });

        test('should block slideshow routes on public host', () => {
            req = createMockRequest('public.example.com', '/api/slideshow');
            hostGate(req, res, next);

            expect(res.status).toHaveBeenCalledWith(403);
        });

        test('should block migration routes on public host', () => {
            req = createMockRequest('public.example.com', '/api/migration/start');
            hostGate(req, res, next);

            expect(res.status).toHaveBeenCalledWith(403);
        });

        test('should block auth login on public host', () => {
            req = createMockRequest('public.example.com', '/api/auth/login');
            hostGate(req, res, next);

            expect(res.status).toHaveBeenCalledWith(403);
        });
    });

    describe('Allowed Routes', () => {
        test('should allow upload route on public host', () => {
            req = createMockRequest('public.example.com', '/api/upload');
            hostGate(req, res, next);

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

        test('should allow manage routes on public host', () => {
            req = createMockRequest('public.example.com', '/api/manage/abc-123');
            hostGate(req, res, next);

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

        test('should allow preview routes on public host', () => {
            req = createMockRequest('public.example.com', '/api/previews/image.jpg');
            hostGate(req, res, next);

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

        test('should allow consent routes on public host', () => {
            req = createMockRequest('public.example.com', '/api/consent');
            hostGate(req, res, next);

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

        test('should allow all routes on internal host', () => {
            req = createMockRequest('internal.example.com', '/api/admin/deletion-log');
            hostGate(req, res, next);

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

    describe('Feature Flags', () => {
        test('should bypass restriction when NODE_ENV is test and not explicitly enabled', () => {
            // Reload module with test environment
            delete require.cache[require.resolve('../../../src/middlewares/hostGate')];
            process.env.NODE_ENV = 'test';
            process.env.ENABLE_HOST_RESTRICTION = 'false'; // Explicitly disabled
            const hostGateTest = require('../../../src/middlewares/hostGate');
            
            req = createMockRequest('public.example.com', '/api/admin/test');
            hostGateTest(req, res, next);

            expect(next).toHaveBeenCalled();
            expect(res.status).not.toHaveBeenCalled();
            expect(req.isInternalHost).toBe(true);
            
            // Restore
            delete require.cache[require.resolve('../../../src/middlewares/hostGate')];
            process.env.NODE_ENV = 'development';
            process.env.ENABLE_HOST_RESTRICTION = 'true';
        });

        test('should work in test environment when explicitly enabled', () => {
            // Reload module with test environment BUT explicitly enabled
            delete require.cache[require.resolve('../../../src/middlewares/hostGate')];
            process.env.NODE_ENV = 'test';
            process.env.ENABLE_HOST_RESTRICTION = 'true'; // Explicitly enabled
            const hostGateTest = require('../../../src/middlewares/hostGate');
            
            req = createMockRequest('public.example.com', '/api/admin/test');
            hostGateTest(req, res, next);

            // Should block because explicitly enabled
            expect(res.status).toHaveBeenCalledWith(403);
            expect(next).not.toHaveBeenCalled();
            
            // Restore
            delete require.cache[require.resolve('../../../src/middlewares/hostGate')];
            process.env.NODE_ENV = 'development';
            process.env.ENABLE_HOST_RESTRICTION = 'true';
        });
    });

    describe('Request Source Tracking', () => {
        test('should set requestSource to "public" for public host', () => {
            req = createMockRequest('public.example.com', '/api/upload');
            hostGate(req, res, next);

            expect(req.requestSource).toBe('public');
        });

        test('should set requestSource to "internal" for internal host', () => {
            req = createMockRequest('internal.example.com', '/api/admin/test');
            hostGate(req, res, next);

            expect(req.requestSource).toBe('internal');
        });

        test('should set requestSource to "internal" when restrictions disabled', () => {
            // Reload module with disabled restriction
            delete require.cache[require.resolve('../../../src/middlewares/hostGate')];
            process.env.ENABLE_HOST_RESTRICTION = 'false';
            const hostGateDisabled = require('../../../src/middlewares/hostGate');
            
            req = createMockRequest('anything.example.com', '/api/test');
            hostGateDisabled(req, res, next);

            expect(req.requestSource).toBe('internal');
            
            // Restore
            delete require.cache[require.resolve('../../../src/middlewares/hostGate')];
            process.env.ENABLE_HOST_RESTRICTION = 'true';
        });
    });
});
