import { NestFactory } from '@nestjs/core';
import { ValidationPipe } from '@nestjs/common';
import { SwaggerModule, DocumentBuilder } from '@nestjs/swagger';
import { ConfigService } from '@nestjs/config';
import { AppModule } from './app.module';
import { Logger } from '@nestjs/common';

async function bootstrap() {
  const app = await NestFactory.create(AppModule);
  const configService = app.get(ConfigService);
  const logger = new Logger('Bootstrap');

  // Global prefix for all routes
  app.setGlobalPrefix('api');

  // Global validation pipe with transformation
  app.useGlobalPipes(
    new ValidationPipe({
      transform: true,
      whitelist: true,
      forbidNonWhitelisted: true,
      transformOptions: {
        enableImplicitConversion: true,
      },
    }),
  );

  // CORS configuration for multi-app support
  app.enableCors({
    origin: [
      'http://localhost:3000', // Next.js Admin Portal
      'http://localhost:19006', // Expo Web
      'exp://192.168.1.100:19000', // Expo Development
      'exp://localhost:19000', // Expo Development
      // Add production URLs here
      configService.get('FRONTEND_URL'),
      configService.get('MOBILE_APP_URL'),
    ].filter(Boolean), // Remove undefined values
    methods: ['GET', 'POST', 'PUT', 'PATCH', 'DELETE', 'OPTIONS'],
    allowedHeaders: [
      'Origin',
      'X-Requested-With',
      'Content-Type',
      'Accept',
      'Authorization',
      'X-Device-Type',
      'X-App-Version',
      'X-Platform',
    ],
    credentials: true,
    maxAge: 86400, // 24 hours
  });

  // Security headers
  app.use((req: any, res: any, next: any) => {
    // Add custom headers to identify device type
    res.setHeader('X-Powered-By', 'POS-System-API');
    
    // Add device type detection
    const userAgent = req.get('User-Agent') || '';
    const deviceType = req.get('X-Device-Type') || '';
    
    if (deviceType === 'mobile' || userAgent.includes('Expo')) {
      res.setHeader('X-Client-Type', 'mobile');
    } else {
      res.setHeader('X-Client-Type', 'web');
    }
    
    next();
  });

  // Swagger documentation setup
  const config = new DocumentBuilder()
    .setTitle('Multi-Tenant POS API')
    .setDescription(`
      Complete API for multi-tenant Point of Sale system.
      
      ## Authentication
      Use JWT tokens in the Authorization header: \`Bearer <token>\`
      
      ## Multi-tenancy
      All endpoints automatically scope data to the authenticated user's tenant.
      
      ## Client Types
      - **Admin Portal**: Full administrative access
      - **Mobile App**: Point of sale operations
      
      ## Rate Limiting
      API requests are rate limited. Check response headers for limits.
    `)
    .setVersion('1.0')
    .setContact(
      'POS System Support',
      'https://yourpos.com',
      'support@yourpos.com'
    )
    .setLicense('MIT', 'https://opensource.org/licenses/MIT')
    .addBearerAuth(
      {
        type: 'http',
        scheme: 'bearer',
        bearerFormat: 'JWT',
        description: 'Enter JWT token',
      },
      'JWT-auth',
    )
    .addTag('Authentication', 'User authentication and authorization')
    .addTag('Sales', 'Point of sale operations')
    .addTag('Products', 'Product management')
    .addTag('Inventory', 'Inventory tracking and management')
    .addTag('Reports', 'Business analytics and reporting')
    .addTag('Admin', 'Administrative operations')
    .addServer('http://localhost:3001/api', 'Development Server')
    .addServer('https://api.yourpos.com/api', 'Production Server')
    .build();

  const document = SwaggerModule.createDocument(app, config, {
    operationIdFactory: (controllerKey: string, methodKey: string) => methodKey,
  });

  // Setup Swagger UI
  SwaggerModule.setup('api/docs', app, document, {
    swaggerOptions: {
      persistAuthorization: true,
      displayRequestDuration: true,
      docExpansion: 'none',
      filter: true,
      showRequestHeaders: true,
      tryItOutEnabled: true,
    },
    customSiteTitle: 'POS API Documentation',
    customfavIcon: '/favicon.ico',
    customJs: [
      'https://cdnjs.cloudflare.com/ajax/libs/swagger-ui/4.15.5/swagger-ui-bundle.min.js',
      'https://cdnjs.cloudflare.com/ajax/libs/swagger-ui/4.15.5/swagger-ui-standalone-preset.min.js',
    ],
    customCssUrl: [
      'https://cdnjs.cloudflare.com/ajax/libs/swagger-ui/4.15.5/swagger-ui.min.css',
    ],
  });

  // Health check endpoint
  app.use('/health', (req: any, res: any) => {
    res.status(200).json({
      status: 'ok',
      timestamp: new Date().toISOString(),
      uptime: process.uptime(),
      version: process.env.npm_package_version || '1.0.0',
      environment: configService.get('NODE_ENV'),
    });
  });

  // Global error handler
  app.use((error: any, req: any, res: any, next: any) => {
    logger.error(`Global error handler: ${error.message}`, error.stack);
    
    if (res.headersSent) {
      return next(error);
    }

    const isDevelopment = configService.get('NODE_ENV') === 'development';
    
    res.status(error.status || 500).json({
      statusCode: error.status || 500,
      message: error.message || 'Internal server error',
      error: error.name || 'Error',
      timestamp: new Date().toISOString(),
      path: req.url,
      ...(isDevelopment && { stack: error.stack }),
    });
  });

  const port = configService.get('PORT') || 3001;
  const host = configService.get('HOST') || '0.0.0.0';

  await app.listen(port, host);

  logger.log(`🚀 Application is running on: http://${host}:${port}`);
  logger.log(`📚 API Documentation available at: http://${host}:${port}/api/docs`);
  logger.log(`❤️  Health check available at: http://${host}:${port}/health`);
  logger.log(`🌍 Environment: ${configService.get('NODE_ENV')}`);
  
  // Log CORS origins for debugging
  if (configService.get('NODE_ENV') === 'development') {
    logger.log('🔧 CORS enabled for origins:');
    logger.log('   - http://localhost:3000 (Admin Portal)');
    logger.log('   - http://localhost:19006 (Expo Web)');
    logger.log('   - exp://localhost:19000 (Expo Development)');
  }
}

// Handle unhandled promise rejections
process.on('unhandledRejection', (reason, promise) => {
  console.error('Unhandled Rejection at:', promise, 'reason:', reason);
  // Application specific logging, throwing an error, or other logic here
});

// Handle uncaught exceptions
process.on('uncaughtException', (error) => {
  console.error('Uncaught Exception:', error);
  process.exit(1);
});

bootstrap();