import { ConfigService } from '@nestjs/config';
import { NestFactory } from '@nestjs/core';
import { SwaggerModule } from '@nestjs/swagger';
import * as express from 'express';
import { existsSync, mkdirSync } from 'fs';
import { networkInterfaces } from 'os';
import { AppLoggerService } from './infrastructure/logging/app-logger.service';
import { RedisService } from './infrastructure/redis/redis.service';
import { configureHttpServer } from './infrastructure/reliability/http-server.config';
import { RedisIoAdapter } from './infrastructure/socket/redis-io.adapter';
import { bootstrap, getLocalIpv4Addresses, getStaticMediaHeaders, isPrivateIpv4Host } from './main';

jest.mock('./app.module', () => ({ AppModule: class AppModule {} }));
jest.mock('@nestjs/core', () => ({ NestFactory: { create: jest.fn() } }));
jest.mock('@nestjs/swagger', () => {
  class DocumentBuilder {
    setTitle() { return this; }
    setDescription() { return this; }
    setVersion() { return this; }
    addBearerAuth() { return this; }
    build() { return { openapi: '3.0.0' }; }
  }
  return {
    DocumentBuilder,
    SwaggerModule: { createDocument: jest.fn(() => ({ paths: {} })), setup: jest.fn() },
  };
});
jest.mock('compression', () => jest.fn(() => 'compression-middleware'));
jest.mock('express', () => ({
  json: jest.fn(() => 'json-middleware'),
  urlencoded: jest.fn(() => 'urlencoded-middleware'),
  static: jest.fn(() => 'static-middleware'),
}));
jest.mock('fs', () => ({
  ...jest.requireActual<typeof import('fs')>('fs'),
  existsSync: jest.fn(),
  mkdirSync: jest.fn(),
}));
jest.mock('os', () => ({
  ...jest.requireActual<typeof import('os')>('os'),
  networkInterfaces: jest.fn(),
}));
jest.mock('./infrastructure/reliability/http-server.config', () => ({ configureHttpServer: jest.fn() }));
jest.mock('./infrastructure/socket/redis-io.adapter', () => ({
  RedisIoAdapter: jest.fn().mockImplementation(() => ({
    connectToRedis: jest.fn().mockResolvedValue(undefined),
  })),
}));

describe('main bootstrap', () => {
  const build = (overrides: Record<string, unknown> = {}) => {
    const values: Record<string, unknown> = {
      'cors.origins': ['https://app.example.com'],
      nodeEnv: 'production',
      'security.bodyLimit': '2mb',
      'performance.compressionEnabled': true,
      'performance.compressionThresholdBytes': 2048,
      'storage.provider': 'local',
      'storage.basePath': '/uploads/',
      publicBaseUrl: 'http://localhost:4000/',
      'email.enabled': true,
      'email.smtpHost': 'smtp.example.com',
      'email.smtpUser': 'smtp-user',
      'email.fromEmail': 'noreply@example.com',
      globalPrefix: 'api/v1',
      responseEnvelopeEnabled: true,
      'redis.enabled': true,
      'redis.socketAdapterEnabled': true,
      'swagger.enabled': true,
      'swagger.path': 'docs',
      'swagger.title': 'Oudelaa API',
      'swagger.description': 'API',
      'swagger.version': '1.0.0',
      port: 4000,
      host: '0.0.0.0',
      ...overrides,
    };
    const config = {
      get: jest.fn((key: string, defaultValue?: unknown) =>
        Object.prototype.hasOwnProperty.call(values, key) ? values[key] : defaultValue,
      ),
    };
    const logger = {
      log: jest.fn(),
      warn: jest.fn(),
      logHttp: jest.fn(),
    };
    const redis = {};
    const httpServer = { keepAliveTimeout: 0, headersTimeout: 0, requestTimeout: 0 };
    const app = {
      get: jest.fn((token: unknown) => {
        if (token === ConfigService) return config;
        if (token === AppLoggerService) return logger;
        if (token === RedisService) return redis;
        return undefined;
      }),
      useLogger: jest.fn(),
      enableShutdownHooks: jest.fn(),
      use: jest.fn(),
      enableCors: jest.fn(),
      setGlobalPrefix: jest.fn(),
      useGlobalPipes: jest.fn(),
      useGlobalInterceptors: jest.fn(),
      useWebSocketAdapter: jest.fn(),
      listen: jest.fn().mockResolvedValue(undefined),
      getHttpServer: jest.fn(() => httpServer),
    };
    (NestFactory.create as jest.Mock).mockResolvedValue(app);
    return { app, config, logger, redis, httpServer };
  };

  beforeEach(() => {
    jest.clearAllMocks();
    (existsSync as jest.Mock).mockReturnValue(false);
    (networkInterfaces as jest.Mock).mockReturnValue({
      Ethernet: [
        { family: 'IPv4', internal: false, address: '192.168.1.20' },
        { family: 'IPv6', internal: false, address: '::1' },
        null,
      ],
      Loopback: [{ family: 'IPv4', internal: true, address: '127.0.0.1' }],
    });
  });

  it('classifies local addresses and static-media response headers', () => {
    expect(getLocalIpv4Addresses()).toEqual(['192.168.1.20']);
    expect(isPrivateIpv4Host('10.0.0.1')).toBe(true);
    expect(isPrivateIpv4Host('192.168.1.1')).toBe(true);
    expect(isPrivateIpv4Host('172.16.0.1')).toBe(true);
    expect(isPrivateIpv4Host('172.31.0.1')).toBe(true);
    expect(isPrivateIpv4Host('172.15.0.1')).toBe(false);
    expect(getStaticMediaHeaders('.mp3', '/audio/song.mp3')).toEqual(
      expect.objectContaining({ contentType: 'audio/mpeg', acceptRanges: true }),
    );
    expect(getStaticMediaHeaders('.gif')).toEqual(expect.objectContaining({ contentType: 'image/gif' }));
    expect(getStaticMediaHeaders('.m3u8')).toEqual(
      expect.objectContaining({ contentType: 'application/vnd.apple.mpegurl', acceptRanges: true }),
    );
    expect(getStaticMediaHeaders('.m4s')).toEqual(expect.objectContaining({ contentType: 'video/iso.segment' }));
    expect(getStaticMediaHeaders('.ts')).toEqual(expect.objectContaining({ contentType: 'video/mp2t' }));
    expect(getStaticMediaHeaders('.unknown')).toEqual({});
  });

  it('boots the production stack with security, local media, Redis sockets, and Swagger', async () => {
    const { app, logger, httpServer } = build();

    await bootstrap();

    expect(NestFactory.create).toHaveBeenCalledWith(expect.any(Function), {
      bufferLogs: true,
      bodyParser: false,
    });
    expect(mkdirSync).toHaveBeenCalledWith(expect.stringMatching(/uploads$/), { recursive: true });
    expect(app.enableCors).toHaveBeenCalledWith(expect.objectContaining({ credentials: true }));
    expect(app.setGlobalPrefix).toHaveBeenCalledWith('api/v1');
    expect(app.useGlobalPipes).toHaveBeenCalled();
    expect(app.useGlobalInterceptors).toHaveBeenCalled();
    expect(app.listen).toHaveBeenCalledWith(4000, '0.0.0.0');
    expect(configureHttpServer).toHaveBeenCalledWith(httpServer, expect.anything());
    expect(logger.warn).toHaveBeenCalledWith(expect.stringContaining('Mobile devices on the LAN'), 'Bootstrap');
    expect(RedisIoAdapter).toHaveBeenCalled();
    const adapter = (RedisIoAdapter as unknown as jest.Mock).mock.results[0].value;
    expect(adapter.connectToRedis).toHaveBeenCalled();
    expect(app.useWebSocketAdapter).toHaveBeenCalledWith(adapter);
    expect(SwaggerModule.createDocument).toHaveBeenCalled();
    expect(SwaggerModule.setup).toHaveBeenCalledWith('docs', app, expect.anything());

    const middleware = app.use.mock.calls
      .filter((call) => typeof call[0] === 'function')
      .map((call) => call[0]);
    expect(middleware).toHaveLength(2);
    const setHeader = jest.fn();
    const next = jest.fn();
    middleware[0]({}, { setHeader } as any, next);
    expect(setHeader).toHaveBeenCalledWith('Strict-Transport-Security', expect.any(String));

    let finish: (() => void) | undefined;
    const request = { headers: { 'x-request-id': 'invalid id' }, method: 'GET', originalUrl: '/health' } as any;
    const response = {
      statusCode: 200,
      setHeader,
      on: jest.fn((_event: string, listener: () => void) => { finish = listener; }),
    } as any;
    middleware[1](request, response, next);
    finish?.();
    expect(request.headers['x-request-id']).toEqual(expect.any(String));
    expect(logger.logHttp).toHaveBeenCalledWith(expect.objectContaining({ method: 'GET', statusCode: 200 }));

    const suppliedIdRequest = {
      headers: { 'x-request-id': 'mobile-client:request-1' },
      method: 'GET',
      originalUrl: '/health',
    } as any;
    middleware[1](suppliedIdRequest, response, next);
    expect(suppliedIdRequest.headers['x-request-id']).toBe('mobile-client:request-1');

    const staticOptions = (express.static as unknown as jest.Mock).mock.calls[0][1];
    const staticHeader = jest.fn();
    staticOptions.setHeaders({ setHeader: staticHeader }, '/uploads/stream.m3u8');
    expect(staticHeader).toHaveBeenCalledWith('Content-Type', 'application/vnd.apple.mpegurl');
    expect(staticHeader).toHaveBeenCalledWith('Accept-Ranges', 'bytes');
  });

  it('boots without optional integrations and warns about a mismatched private public URL', async () => {
    const { app, logger } = build({
      'cors.origins': [],
      nodeEnv: 'development',
      'performance.compressionEnabled': false,
      'storage.provider': 's3',
      publicBaseUrl: 'http://192.168.1.99:4000',
      responseEnvelopeEnabled: false,
      'redis.enabled': false,
      'redis.socketAdapterEnabled': false,
      'swagger.enabled': false,
      'email.enabled': false,
      'email.smtpHost': '',
      'email.smtpUser': '',
      'email.fromEmail': '',
    });

    await bootstrap();

    expect(mkdirSync).not.toHaveBeenCalled();
    expect(app.enableCors).toHaveBeenCalledWith(expect.objectContaining({ origin: true, credentials: true }));
    expect(app.useGlobalInterceptors).not.toHaveBeenCalled();
    expect(app.useWebSocketAdapter).not.toHaveBeenCalled();
    expect(SwaggerModule.setup).not.toHaveBeenCalled();
    expect(logger.warn).toHaveBeenCalledWith(expect.stringContaining('not assigned to the current machine'), 'Bootstrap');
  });
});
