import express from 'express';
import cors from 'cors';
import helmet from 'helmet';
import cookieParser from 'cookie-parser';
import rateLimit from 'express-rate-limit';
import dotenv from 'dotenv';
import path from 'path';
import { PrismaClient } from '@prisma/client';
import logger from './utils/logger';
import { errorHandler } from './middlewares/errorHandler';
import { notFoundHandler } from './middlewares/notFoundHandler';
import { websocketService } from './services/websocketService';


// Import routes
import authRoutes from './routes/auth';
import userRoutes from './routes/users';
import botRoutes from './routes/bots';
import conversationRoutes from './routes/conversations';
import feedbackRoutes from './routes/feedback';
import elevenLabsRoutes from './routes/elevenlabs';
import elevenLabsVoiceRoutes from './routes/elevenlabs-voice';
import botAssignmentRoutes from './routes/bot-assignments';
import statisticsRoutes from './routes/statistics';
import usageRoutes from './routes/usage';
import notificationRoutes from './routes/notifications';
import openaiRoutes from './routes/openai';
import systemConfigRoutes from './routes/systemConfig';

// Import seeding function
import { seedDatabase } from './prisma/seed';

// Load environment variables
dotenv.config();

logger.info('🚀 Starting AI Learning Platform Backend Server', {
  nodeEnv: process.env.NODE_ENV,
  port: process.env.PORT,
  host: process.env.HOST,
  corsOrigin: process.env.CORS_ORIGIN,
  logLevel: process.env.LOG_LEVEL,
  databaseUrl: process.env.DATABASE_URL ? 'configured' : 'not configured'
});

// Initialize Prisma client
export const prisma = new PrismaClient({
  log: process.env.NODE_ENV === 'development' 
    ? ['query', 'info', 'warn', 'error'] 
    : ['warn', 'error'],
});

logger.info('📊 Prisma client initialized with logging enabled');

// Create Express app
const app = express();
const PORT = parseInt(process.env.PORT || '3000', 10);
const HOST = process.env.HOST || '0.0.0.0';

logger.info('🔧 Configuring Express middleware', {
  port: PORT,
  host: HOST,
  environment: process.env.NODE_ENV
});

// CORS configuration
const corsOrigin = process.env.CORS_ORIGIN || 'http://localhost:5173,http://localhost,http://127.0.0.1:5173,http://127.0.0.1';
const corsOrigins = corsOrigin.split(',').map(origin => origin.trim()).filter(Boolean);

const corsOptions: cors.CorsOptions = {
  origin: function (origin, callback) {
    // Allow requests with no origin (like mobile apps or curl requests)
    if (!origin) return callback(null, true);

    // Exact match
    if (corsOrigins.includes(origin)) return callback(null, true);

    try {
      const url = new URL(origin);
      // Allow any localhost / 127.0.0.1 (any port, http/https) for development
      if (url.hostname === 'localhost' || url.hostname === '127.0.0.1') {
        return callback(null, true);
      }
    } catch {}

    return callback(new Error('Not allowed by CORS'));
  },
  credentials: true,
  methods: ['GET', 'POST', 'PUT', 'DELETE', 'PATCH', 'OPTIONS'],
  allowedHeaders: ['Content-Type', 'Authorization'],
};

app.use(cors(corsOptions));
// Explicitly enable preflight across all routes
app.options('*', cors(corsOptions));

// Security middleware
app.use(helmet({
  crossOriginEmbedderPolicy: false,
  contentSecurityPolicy: {
    directives: {
      defaultSrc: ["'self'"],
      connectSrc: ["'self'", 'http:', 'https:', 'ws:', 'wss:'],
      styleSrc: ["'self'", "'unsafe-inline'"],
      scriptSrc: ["'self'"],
      imgSrc: ["'self'", "data:", "https:"],
    },
  },
}));

logger.info('🛡️ Helmet security middleware configured');

logger.info('🌐 CORS configured', {
  origin: corsOrigin,
  credentials: true,
  methods: ['GET', 'POST', 'PUT', 'DELETE', 'PATCH', 'OPTIONS']
});

// Rate limiting (disabled in development)
if (process.env.NODE_ENV === 'production') {
  const windowMs = parseInt(process.env.RATE_LIMIT_WINDOW_MS || '900000');
  const maxRequests = parseInt(process.env.RATE_LIMIT_MAX_REQUESTS || '100');
  
  const limiter = rateLimit({
    windowMs,
    max: maxRequests,
    message: {
      error: 'Too many requests from this IP, please try again later.',
    },
    standardHeaders: true,
    legacyHeaders: false,
  });
  app.use(limiter);
  
  logger.info('⚡ Rate limiting enabled for production', {
    environment: process.env.NODE_ENV,
    maxRequests,
    windowMs: `${windowMs}ms`
  });
}

// Body parsing middleware
app.use(express.json({ limit: '10mb' }));
app.use(express.urlencoded({ extended: true, limit: '10mb' }));
logger.info('📝 Body parsing middleware configured', {
  jsonLimit: '10mb',
  urlencodedLimit: '10mb'
});

// Cookie parser
app.use(cookieParser());

// Static file serving for uploaded images
app.use('/uploads', express.static(path.join(__dirname, '../uploads')));

// Static file serving for system assets
app.use('/assets', express.static(path.join(__dirname, 'assets')));

// Enhanced request logging with performance tracking
app.use((req, res, next) => {
  const startTime = Date.now();
  const requestId = Math.random().toString(36).substring(7);
  
  logger.info('📥 Incoming request', {
    requestId,
    method: req.method,
    path: req.path,
    query: Object.keys(req.query).length > 0 ? req.query : undefined,
    ip: req.ip,
    userAgent: req.get('User-Agent'),
    origin: req.get('Origin'),
    referer: req.get('Referer'),
    contentType: req.get('Content-Type'),
    contentLength: req.get('Content-Length'),
    authorization: req.headers.authorization ? 'present' : 'absent',
    cookies: Object.keys(req.cookies || {}).length > 0 ? Object.keys(req.cookies) : undefined
  });

  // Track response time
  res.on('finish', () => {
    const responseTime = Date.now() - startTime;
    const statusCode = res.statusCode;
    const contentLength = res.get('Content-Length');
    
    logger.info('📤 Request completed', {
      requestId,
      method: req.method,
      path: req.path,
      statusCode,
      responseTime: `${responseTime}ms`,
      contentLength,
      userAgent: req.get('User-Agent'),
      ip: req.ip
    });
  });

  next();
});

// Health check endpoint
app.get('/health', (req, res) => {
  res.status(200).json({ 
    status: 'healthy', 
    timestamp: new Date().toISOString(),
    uptime: process.uptime()
  });
});
logger.info('🏥 Health check endpoint configured at /health');

// API routes
logger.info('🛣️ Configuring API routes');

app.use('/api/auth', authRoutes);
logger.info('✅ Auth routes mounted at /api/auth');

app.use('/api/users', userRoutes);
logger.info('✅ User routes mounted at /api/users');

app.use('/api/bots', botRoutes);
logger.info('✅ Bot routes mounted at /api/bots');

app.use('/api/conversations', conversationRoutes);
logger.info('✅ Conversation routes mounted at /api/conversations');

app.use('/api/feedback', feedbackRoutes);
logger.info('✅ Feedback routes mounted at /api/feedback');

app.use('/api/elevenlabs', elevenLabsRoutes);
app.use('/api/elevenlabs-voice', elevenLabsVoiceRoutes);
app.use('/api/usage', usageRoutes);
logger.info('✅ ElevenLabs routes mounted at /api/elevenlabs');

app.use('/api/bot-assignments', botAssignmentRoutes);
logger.info('✅ Bot assignment routes mounted at /api/bot-assignments');

app.use('/api/statistics', statisticsRoutes);
logger.info('✅ Statistics routes mounted at /api/statistics');

app.use('/api/notifications', notificationRoutes);
logger.info('✅ Notification routes mounted at /api/notifications');

app.use('/api/openai', openaiRoutes);
logger.info('✅ OpenAI routes mounted at /api/openai');

app.use('/api/system-config', systemConfigRoutes);
logger.info('✅ System configuration routes mounted at /api/system-config');

// 404 handler
app.use(notFoundHandler);
logger.info('✅ 404 handler configured');

// Error handling middleware
app.use(errorHandler);
logger.info('✅ Error handler configured');

// Database seeding function
async function initializeDatabase() {
  try {
    logger.info('🌱 Starting database initialization...');
    await seedDatabase();
    logger.info('✅ Database initialization completed successfully');
  } catch (error) {
    logger.error('❌ Database initialization failed', { error });
    // Don't exit the process, just log the error
  }
}

// Graceful shutdown
process.on('SIGTERM', async () => {
  logger.info('🛑 SIGTERM received, shutting down gracefully', {
    uptime: `${process.uptime()}s`,
    memoryUsage: process.memoryUsage()
  });
  
  try {
    await prisma.$disconnect();
    logger.info('✅ Database connection closed successfully');
    process.exit(0);
  } catch (error) {
    logger.error('❌ Error during graceful shutdown', { error });
    process.exit(1);
  }
});

process.on('SIGINT', async () => {
  logger.info('🛑 SIGINT received, shutting down gracefully', {
    uptime: `${process.uptime()}s`,
    memoryUsage: process.memoryUsage()
  });
  
  try {
    await prisma.$disconnect();
    logger.info('✅ Database connection closed successfully');
    process.exit(0);
  } catch (error) {
    logger.error('❌ Error during graceful shutdown', { error });
    process.exit(1);
  }
});

// Start server
const server = app.listen(PORT, HOST, async () => {
  logger.info('🎉 Server started successfully', {
    url: `http://${HOST}:${PORT}`,
    environment: process.env.NODE_ENV,
    corsOrigin: process.env.CORS_ORIGIN,
    logLevel: process.env.LOG_LEVEL,
    nodeVersion: process.version,
    platform: process.platform,
    memoryUsage: process.memoryUsage()
  });
  
  // Initialize database seeding
  await initializeDatabase();
  
  // Initialize WebSocket server
  websocketService.initialize(server);
});

// Handle unhandled promise rejections
process.on('unhandledRejection', (err: Error) => {
  logger.error('💥 Unhandled Promise Rejection', {
    error: err.message,
    stack: err.stack,
    uptime: `${process.uptime()}s`,
    memoryUsage: process.memoryUsage()
  });
  
  server.close(() => {
    logger.info('🛑 Server closed due to unhandled rejection');
    process.exit(1);
  });
});

// Handle uncaught exceptions
process.on('uncaughtException', (err: Error) => {
  logger.error('💥 Uncaught Exception', {
    error: err.message,
    stack: err.stack,
    uptime: `${process.uptime()}s`,
    memoryUsage: process.memoryUsage()
  });
  
  server.close(() => {
    logger.info('🛑 Server closed due to uncaught exception');
    process.exit(1);
  });
});

process.on('beforeExit', async () => {
  await prisma.$disconnect();
});
process.on('SIGINT', async () => {
  await prisma.$disconnect();
  process.exit(0);
});

export default app;
