const express = require('express')
const cors = require('cors')
const helmet = require('helmet')
const morgan = require('morgan')
const compression = require('compression')
const rateLimit = require('express-rate-limit')
const session = require('express-session')
// const { createServer } = require('http')

const config = require('./config/config')
const { testConnection } = require('./config/database')
const Role = require('./models/Role')

// Import routes
const authRoutes = require('./routes/auth')
const dashboardRoutes = require('./routes/dashboard')
const securityRoutes = require('./routes/security')
const roleRoutes = require('./routes/roles')
const contactRoutes = require('./routes/contacts')
const superAdminRoutes = require('./routes/superAdmin')
const organizationRoutes = require('./routes/organizations')
const organizationalRoutes = require('./routes/organizational')
const unitRoutes = require('./routes/units')
const departmentRoutes = require('./routes/departments')
const userRoutes = require('./routes/users')
const rankRoutes = require('./routes/ranks')
const userExcelRoutes = require('./routes/userExcel')
const messageRoutes = require('./routes/messages')
const conversationRoutes = require('./routes/conversations')
const notificationRoutes = require('./routes/notifications')
const designationRoutes = require('./routes/designations')
const utilityRoutes = require('./routes/utility')
const locationRoutes = require('./routes/locations')
// Load group contacts routes
let groupContactRoutes
try {
  groupContactRoutes = require('./routes/groupContacts')
  console.log('✅ Group contacts routes module loaded successfully')
} catch (error) {
  console.error('❌ Error loading group contacts routes:', error)
  console.error('Error stack:', error.stack)
  // Create a dummy router to prevent server crash
  const express = require('express')
  groupContactRoutes = express.Router()
  groupContactRoutes.get('*', (req, res) => {
    res.status(500).json({
      status: 'error',
      message: 'Group contacts routes failed to load. Please check server logs.'
    })
  })
}

const app = express()

// Test database connection
testConnection();

// Ensure DB constraints
(async () => {
  try {
    await Role.ensureUniqueIndex()
    console.log('✅ Ensured unique index on roles (organization_id, name)')
  } catch (e) {
    console.warn('⚠️ Could not ensure unique index on roles:', e && e.message)
  }
})()

// Security middleware
app.use(helmet({
  crossOriginResourcePolicy: { policy: 'cross-origin' }
}))

// CORS configuration
app.use(cors(config.cors))

// Rate limiting - More lenient general limit
const generalLimiter = rateLimit({
  windowMs: config.rateLimit.general.windowMs,
  max: config.rateLimit.general.maxRequests,
  message: {
    status: 'error',
    message: 'Too many requests. Please wait a moment and try again.',
    retryAfter: Math.ceil(config.rateLimit.general.windowMs / 1000)
  },
  standardHeaders: true,
  legacyHeaders: false,
  keyGenerator: (req) => `${req.user?.id || req.ip}-general`,
  skip: (req) => {
    const url = req.originalUrl || ''
    // Skip rate limiting for lightweight profile and health-related reads
    return (
      url.startsWith('/api/health') ||
      url.startsWith('/api/auth/profile') ||
      url.startsWith('/api/dashboard/stats') ||
      url.startsWith('/api/dashboard/analytics') ||
      (req.method === 'GET' && url.startsWith('/api/contacts'))
    )
  }
})

// Apply general rate limiting to all API routes
app.use('/api/', generalLimiter)

// Body parsing middleware
// Note: These should NOT parse multipart/form-data - multer handles that
app.use(express.json({ limit: '10mb' }))
app.use(express.urlencoded({ extended: true, limit: '10mb' }))

// Compression middleware
app.use(compression())

// Logging middleware
if (config.nodeEnv === 'development') {
  app.use(morgan('dev'))
} else {
  app.use(morgan('combined'))
}

// Session configuration (using memory store for now)
app.use(session({
  secret: config.session.secret,
  resave: config.session.resave,
  saveUninitialized: config.session.saveUninitialized,
  cookie: config.session.cookie
}))

// Serve static files from uploads directory
const path = require('path')
const uploadsPath = path.isAbsolute(config.upload.uploadPath)
  ? config.upload.uploadPath
  : path.join(__dirname, '..', config.upload.uploadPath)
app.use('/uploads', express.static(uploadsPath))

// Serve static files from public directory
const publicPath = path.join(__dirname, '..', 'public')
const imagesStaticOptions = {
  setHeaders: (res, _filePath) => {
    // Set CORS headers for images
    res.setHeader('Access-Control-Allow-Origin', '*')
    res.setHeader('Access-Control-Allow-Methods', 'GET')
    res.setHeader('Cross-Origin-Resource-Policy', 'cross-origin')
    res.setHeader('Cache-Control', 'public, max-age=31536000')
  }
}
app.use('/Images', express.static(path.join(publicPath, 'Images'), imagesStaticOptions))
// Alias for clients that incorrectly prefix API base to image paths
app.use('/api/Images', express.static(path.join(publicPath, 'Images'), imagesStaticOptions))

// Fallback: if /Images/contacts/<file> is missing, serve from /Images/user/<file>
try {
  const fs = require('fs')
  const sendWithHeaders = (res, filePath) => {
    res.setHeader('Access-Control-Allow-Origin', '*')
    res.setHeader('Access-Control-Allow-Methods', 'GET')
    res.setHeader('Cross-Origin-Resource-Policy', 'cross-origin')
    res.setHeader('Cache-Control', 'public, max-age=31536000')
    res.sendFile(filePath)
  }
  const contactsFallbackHandler = (req, res) => {
    const file = path.basename(req.params.filename || '')
    if (!file) {
      return res.status(404).json({ status: 'error', message: 'File not specified' })
    }
    const contactsPathAbs = path.join(publicPath, 'Images', 'contacts', file)
    if (fs.existsSync(contactsPathAbs)) {
      return sendWithHeaders(res, contactsPathAbs)
    }
    const userPathAbs = path.join(publicPath, 'Images', 'user', file)
    if (fs.existsSync(userPathAbs)) {
      return sendWithHeaders(res, userPathAbs)
    }
    return res.status(404).json({ status: 'error', message: 'Image not found', file })
  }
  app.get('/Images/contacts/:filename', contactsFallbackHandler)
  app.get('/api/Images/contacts/:filename', contactsFallbackHandler)
  // Also support /Images/user with fallback to contacts if missing
  const userFallbackHandler = (req, res) => {
    const file = path.basename(req.params.filename || '')
    if (!file) {
      return res.status(404).json({ status: 'error', message: 'File not specified' })
    }
    const userPathAbs = path.join(publicPath, 'Images', 'user', file)
    if (fs.existsSync(userPathAbs)) {
      return sendWithHeaders(res, userPathAbs)
    }
    const contactsPathAbs = path.join(publicPath, 'Images', 'contacts', file)
    if (fs.existsSync(contactsPathAbs)) {
      return sendWithHeaders(res, contactsPathAbs)
    }
    return res.status(404).json({ status: 'error', message: 'Image not found', file })
  }
  app.get('/Images/user/:filename', userFallbackHandler)
  app.get('/api/Images/user/:filename', userFallbackHandler)
} catch (e) {
  console.error('⚠️ Could not register contacts fallback handler:', e)
}

// Health check endpoint (must be before other /api routes)
app.get('/api/health', (req, res) => {
  res.status(200).json({
    status: 'success',
    message: 'CMS Backend API is running',
    timestamp: new Date().toISOString(),
    environment: config.nodeEnv
  })
})

// Root endpoint
app.get('/', (req, res) => {
  res.status(200).json({
    status: 'success',
    message: 'CMS Backend API',
    health: '/api/health'
  })
})

// Routes
app.use('/api/auth', authRoutes)
app.use('/api/dashboard', dashboardRoutes)
app.use('/api/security', securityRoutes)
app.use('/api/roles', roleRoutes) // Made more specific to avoid catching /api/health
app.use('/api/contacts', contactRoutes)
app.use('/api/super-admin', superAdminRoutes)
app.use('/api/organizations', organizationRoutes)
app.use('/api/organizational', organizationalRoutes)
app.use('/api/units', unitRoutes)
app.use('/api/departments', departmentRoutes)
app.use('/api/users', userRoutes)
app.use('/api/ranks', rankRoutes)
app.use('/api/users/excel', userExcelRoutes)
app.use('/api/messages', messageRoutes)
app.use('/api/conversations', conversationRoutes)
app.use('/api/notifications', notificationRoutes)
app.use('/api/designations', designationRoutes)
app.use('/api/utility', utilityRoutes)
app.use('/api/group-contacts', groupContactRoutes)
app.use('/api/locations', locationRoutes)

// Debug: Log all registered routes
console.log('✅ Group Contacts route registered at: /api/group-contacts')

// 404 handler
app.use('*', (req, res) => {
  console.log('❌ 404 - Route not found:', req.method, req.originalUrl)
  console.log('❌ Available routes include: /api/group-contacts')
  res.status(404).json({
    status: 'error',
    message: 'Route not found',
    path: req.originalUrl,
    method: req.method
  })
})

// Global error handler
app.use((err, req, res, _next) => {
  console.error('Error:', err)

  res.status(err.status || 500).json({
    status: 'error',
    message: err.message || 'Internal server error',
    ...(config.nodeEnv === 'development' && { stack: err.stack })
  })
})

// Start server with port fallback
const startServer = (port) => {
  const server = app.listen(port, () => {
    console.log(`🚀 Server running on port ${port}`)
    console.log(`📊 Environment: ${config.nodeEnv}`)
    console.log(`🔗 Health check: http://localhost:${port}/api/health`)
  })

  server.on('error', (err) => {
    if (err.code === 'EADDRINUSE') {
      const nextPort = parseInt(port) + 1
      if (nextPort > 65535) {
        console.error('❌ No available ports found. Please free up port 3000.')
        process.exit(1)
      }
      console.log(`⚠️  Port ${port} is already in use. Trying port ${nextPort}...`)
      startServer(nextPort)
    } else {
      console.error('Server error:', err)
      process.exit(1)
    }
  })

  return server
}

const PORT = config.port
const server = startServer(PORT)

module.exports = { app, server }
