import express from 'express';
import cors from 'cors';
import helmet from 'helmet';
import cookieParser from 'cookie-parser';
import http from 'http';
import { Server } from 'socket.io';
import swaggerUi from 'swagger-ui-express';
import { swaggerSpec } from './src/config/swagger';
import jwt from 'jsonwebtoken';
import dotenv from 'dotenv';
dotenv.config();
import connectDB from './src/config/db';
import User from './src/models/users';
import { setSocketServer, userRoom } from './src/utils/socket';

const app = express();
const server = http.createServer(app);

const allowedOrigins = [process.env.ADMIN_URL, process.env.USER_URL, process.env.URL].filter(Boolean) as string[];

const io = new Server(server, {
  cors: {
    origin: allowedOrigins.length ? allowedOrigins : '*',
  },
});
setSocketServer(io);

// Make io accessible in controllers
app.set('io', io);

io.use(async (socket, next) => {
  try {
    const authToken = socket.handshake.auth?.token as string | undefined;
    const bearerToken = socket.handshake.headers.authorization?.startsWith('Bearer ')
      ? socket.handshake.headers.authorization.split(' ')[1]
      : undefined;
    const token = authToken || bearerToken;

    if (!token) return next();

    const decoded = jwt.verify(token, process.env.JWT_SECRET!) as { id: string; tokenVersion: number };
    const user = await User.findById(decoded.id).select('tokenVersion role status');

    if (!user) return next();
    if (decoded.tokenVersion !== user.tokenVersion) return next();
    if (user.role !== 'user' || user.status !== 'active') return next();

    socket.data.userId = user._id.toString();
    return next();
  } catch {
    return next();
  }
});

io.on('connection', (socket) => {
  const socketUserId = socket.data.userId as string | undefined;
  if (socketUserId) {
    socket.join(userRoom(socketUserId));
  }
  console.log('Client connected:', socket.id);
  socket.on('disconnect', () => console.log('Client disconnected:', socket.id));
});

app.use('/api-docs', swaggerUi.serve, swaggerUi.setup(swaggerSpec));
app.use(helmet());
app.use(cors({
  origin: (origin, callback) => {
    if (!origin || allowedOrigins.includes(origin)) {
      callback(null, true);
    } else {
      callback(new Error('Not allowed by CORS'));
    }
  },
  credentials: true,
}));
app.use(cookieParser());
app.use(express.json());

connectDB();

import authRoutes from './src/Routes/authRoutes';
import adminRoutes from './src/Routes/adminRoutes';
import userRoutes from './src/Routes/userRoutes';
import questionRoutes from './src/Routes/questionRoutes';
import quizRoutes from './src/Routes/quizRoutes';
import psychometricRoutes from './src/Routes/psychometricRoutes';
import attendanceRoutes from './src/Routes/attendanceRoutes';
import notificationRoutes from './src/Routes/notificationRoutes';
import { startQuizExpiryCron } from './src/cron/quizExpiry';
import { startNotificationCron } from './src/cron/notificationScheduler';
import rewardRoutes from './src/Routes/rewardRoutes';
import rewardAdminRoutes from './src/Routes/rewardAdminRoutes';
import rewardStoreRoutes from './src/Routes/rewardStoreRoutes';
import gameRoutes from './src/Routes/gameRoutes';
import legalPageRoutes from './src/Routes/legalPageRoutes';
import departmentDesignationRoutes from './src/Routes/departmentDesignationRoutes';
// Routes
app.use('/api/auth', authRoutes);
app.use('/api/admin', adminRoutes);
app.use('/api/user', userRoutes);
app.use('/api/questions', questionRoutes);
app.use('/api/quizzes', quizRoutes);
app.use('/api/psychometric', psychometricRoutes);
app.use('/api/attendance', attendanceRoutes);
app.use('/api/notifications', notificationRoutes);
app.use('/api/rewards', rewardRoutes);
app.use('/api/admin', rewardAdminRoutes);
app.use('/api/rewards', rewardStoreRoutes);
app.use('/api/games', gameRoutes);
app.use('/api', legalPageRoutes);
app.use('/api', departmentDesignationRoutes);

// 404 handler
app.use((_req: express.Request, res: express.Response) => {
  res.status(404).json({ success: false, status_code: 404, message: 'Route not found', data: null, errors: 'Route not found', pagination: null });
});

// Global error handler
app.use((err: any, _req: express.Request, res: express.Response, _next: express.NextFunction) => {
  let statusCode = err.statusCode || 500;
  let message = err.message || 'Something went wrong';

  // MongoDB duplicate key error
  if (err.code === 11000) {
    statusCode = 400;
    const field = Object.keys(err.keyPattern || {})[0] || 'field';
    message = `${field} already exists`;
  }
  // Mongoose validation error
  if (err.name === 'ValidationError') {
    statusCode = 400;
    message = Object.values(err.errors || {}).map((e: any) => e.message).join(', ');
  }

  res.status(statusCode).json({
    success: false,
    status_code: statusCode,
    message,
    data: null,
    errors: message,
    pagination: null,
  });
});

server.listen(process.env.PORT, () => {
  console.log(`Server starts running on port ${process.env.PORT}`);
  startQuizExpiryCron();
  startNotificationCron();
});
