require('dotenv').config();

const express = require('express');
const cors = require('cors');
const helmet = require('helmet');
const morgan = require('morgan');
const compression = require('compression');
const { testConnection } = require('./config/database');
const config = require('./config/config');
const path = require('path');
const errorHandler = require('./middleware/errorHandler');
const { Booking, Schedule, User, UserNotification, ScheduleStop } = require('./models');
const { Op } = require('sequelize');
const { notifyBookingReminder, notifyTripStarted, notifyTripEnded } = require('./services/PushNotificationService');
const EmailService = require('./services/EmailService');

const app = express();

app.use('/uploads', express.static(path.join(__dirname, 'uploads')));

app.use(helmet());
app.use(compression());
app.use(cors({
  origin: process.env.FRONTEND_URL || 'http://localhost:5173',
  credentials: true,
}));
app.use(morgan('dev'));
app.use(express.json());
app.use(express.urlencoded({ extended: true }));

app.get('/api/health', (req, res) => {
  res.json({
    status: 'ok',
    service: 'Tok Tokkie Shuttles API',
    version: '1.0.0',
    timestamp: new Date().toISOString(),
  });
});

app.use('/api', require('./routes'));

app.use(errorHandler);

const startServer = async () => {
  await testConnection();
  await UserNotification.sync({ alter: true });
  console.log('[Server] User notifications model synced');
  await ScheduleStop.sync({ alter: true });
  console.log('[Server] Schedule stops model synced');
  console.log('[Server] Models synced');

  app.listen(config.port, () => {
    console.log(`[Server] Tok Tokkie API running on port ${config.port}`);
    console.log(`[Server] Health check: http://localhost:${config.port}/api/health`);
  });

  const CHECK_INTERVAL = 60 * 1000;
  setInterval(async () => {
    try {
      const now = new Date();
      const dayNames = ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday'];

      const bookings = await Booking.findAll({
        where: {
          booking_status: { [Op.notIn]: ['cancelled', 'completed'] },
        },
        include: [{ model: Schedule }],
      });

      for (const booking of bookings) {
        const schedule = booking.schedule;
        if (!schedule) continue;

        const departureIndex = dayNames.indexOf(schedule.departure_day);
        if (departureIndex === -1) continue;

        const nextDeparture = new Date(now);
        const todayIndex = now.getDay();
        let daysUntil = (departureIndex - todayIndex + 7) % 7;
        if (daysUntil === 0) {
          const [h, m] = (schedule.departure_time || '00:00').split(':').map(Number);
          const depTime = new Date(now);
          depTime.setHours(h, m, 0, 0);
          if (depTime <= now) daysUntil = 7;
        }
        nextDeparture.setDate(now.getDate() + daysUntil);
        const [depH, depM] = (schedule.departure_time || '00:00').split(':').map(Number);
        nextDeparture.setHours(depH, depM, 0, 0);

        const msUntil = nextDeparture.getTime() - now.getTime();
        const hoursUntil = Math.round(msUntil / (1000 * 60 * 60));

        if (hoursUntil === 24 && !booking.reminder_24h_sent_at) {
          await notifyBookingReminder(booking, 24);
          await booking.update({ reminder_24h_sent_at: new Date() });
        }

        if (hoursUntil === 2 && !booking.reminder_2h_sent_at) {
          await notifyBookingReminder(booking, 2);
          await booking.update({ reminder_2h_sent_at: new Date() });
        }

        if (hoursUntil === 0 && daysUntil === 0 && !booking.trip_started_notified_at) {
          await notifyTripStarted(booking);
          await EmailService.notifyTripStatus(
            booking.customer_email, booking.customer_name,
            booking.booking_reference, 'Started'
          );
          await booking.update({ trip_started_notified_at: new Date() });
        }
      }

      const completedBookings = await Booking.findAll({
        where: {
          booking_status: 'completed',
          trip_ended_notified_at: null,
        },
        include: [{ model: Schedule }],
      });

      for (const booking of completedBookings) {
        await notifyTripEnded(booking);
        await booking.update({ trip_ended_notified_at: new Date() });
      }
    } catch (e) {
      console.error('[Background] Check error:', e.message);
    }
  }, CHECK_INTERVAL);
};

startServer();

module.exports = app;
