/**
 * Calendar Controller
 * Events and calendar management
 */

const express = require('express');
const router = express.Router();
const { v4: uuidv4 } = require('uuid');

// Database path
const dbPath = process.env.DB_PATH || require('path').join(__dirname, '../../data/school.db');
const Database = require('better-sqlite3');
let db;

const getDb = () => {
  if (!db) {
    db = new Database(dbPath);
    db.pragma('foreign_keys = ON');
  }
  return db;
};

// Auth middleware
const auth = (req, res, next) => {
  const token = req.headers.authorization?.split(' ')[1];
  if (!token) return res.status(401).json({ error: 'No token provided' });
  try {
    const jwt = require('jsonwebtoken');
    const { jwtSecret: JWT_SECRET } = require('../config');
    req.user = jwt.verify(token, JWT_SECRET);
    next();
  } catch (err) {
    res.status(401).json({ error: 'Invalid token' });
  }
};

// Admin or teacher only
const adminOrTeacher = (req, res, next) => {
  if (!['school_admin', 'systems_admin'].includes(req.user.role) && req.user.role !== 'teacher') {
    return res.status(403).json({ error: 'Admin or Teacher access required' });
  }
  next();
};

// Admin-only middleware
const adminOnly = (req, res, next) => {
  if (!['school_admin', 'systems_admin'].includes(req.user.role)) {
    return res.status(403).json({ error: 'Admin access required' });
  }
  next();
};

// ============ EVENTS CRUD ============

/**
 * @openapi
 * /api/calendar:
 *   get:
 *     summary: List events
 *     description: |
 *       Returns active events ordered by `event_date` ascending.
 *       Non-admin callers only see public events plus events they
 *       themselves created. Optional filters: `start_date`,
 *       `end_date`, `event_type`, free-text `search` against
 *       title/description, and `month`/`year` for a calendar-month
 *       window. Each row includes `created_by_name` and a count of
 *       other events on the same day (`same_day_count`).
 *     tags:
 *       - Calendar
 *     security:
 *       - bearerAuth: []
 *     parameters:
 *       - in: query
 *         name: start_date
 *         schema: { type: string, format: date }
 *       - in: query
 *         name: end_date
 *         schema: { type: string, format: date }
 *       - in: query
 *         name: event_type
 *         schema: { type: string }
 *       - in: query
 *         name: search
 *         schema: { type: string }
 *       - in: query
 *         name: month
 *         schema: { type: string }
 *       - in: query
 *         name: year
 *         schema: { type: string }
 *     responses:
 *       200:
 *         description: Event list
 *         content:
 *           application/json:
 *             schema:
 *               type: array
 *               items: { type: object }
 *       401: { description: Unauthorized }
 *       500: { description: Server error }
 *   post:
 *     summary: Create event
 *     description: |
 *       Creates an event. Restricted to admin or teacher roles.
 *       `is_public` controls whether non-privileged callers can see
 *       the event; `academic_year` is used by the academic calendar
 *       grid endpoint.
 *     tags:
 *       - Calendar
 *     security:
 *       - bearerAuth: []
 *     requestBody:
 *       required: true
 *       content:
 *         application/json:
 *           schema:
 *             type: object
 *             required:
 *               - title
 *               - event_date
 *             properties:
 *               title: { type: string }
 *               description: { type: string }
 *               event_date: { type: string, format: date }
 *               end_date: { type: string, format: date }
 *               event_type: { type: string }
 *               venue: { type: string }
 *               is_public: { type: boolean }
 *               academic_year: { type: string }
 *     responses:
 *       201:
 *         description: Created event
 *         content:
 *           application/json:
 *             schema: { type: object }
 *       400: { description: Title and event_date are required }
 *       401: { description: Unauthorized }
 *       403: { description: Admin or Teacher only }
 *       500: { description: Server error }
 */
// List events
router.get('/', auth, (req, res) => {
  try {
    const { start_date, end_date, event_type, search, month, year } = req.query;
    
    let query = `
      SELECT e.*, 
        u.first_name || ' ' || u.last_name as created_by_name,
        (SELECT COUNT(*) FROM events WHERE event_date = e.event_date AND is_deleted = 0) as same_day_count
      FROM events e
      LEFT JOIN users u ON e.created_by = u.id
      WHERE e.is_deleted = 0
    `;
    const params = [];
    
    // Public events visible to all, others only to creator
    if (!['school_admin', 'systems_admin'].includes(req.user.role)) {
      query += ' AND (e.is_public = 1 OR e.created_by = ?)';
      params.push(req.user.id);
    }
    
    if (start_date) {
      query += ' AND e.event_date >= ?';
      params.push(start_date);
    }
    if (end_date) {
      query += ' AND e.event_date <= ?';
      params.push(end_date);
    }
    if (month && year) {
      query += " AND strftime('%m', e.event_date) = ? AND strftime('%Y', e.event_date) = ?";
      params.push(month.padStart(2, '0'), year);
    }
    if (event_type) {
      query += ' AND e.event_type = ?';
      params.push(event_type);
    }
    if (search) {
      query += ' AND (e.title LIKE ? OR e.description LIKE ?)';
      const searchTerm = `%${search}%`;
      params.push(searchTerm, searchTerm);
    }
    
    query += ' ORDER BY e.event_date ASC, e.title';
    
    const events = getDb().prepare(query).all(...params);
    res.json(events);
  } catch (error) {
    res.status(500).json({ error: error.message });
  }
});


/**
 * @openapi
 * /api/calendar/{id}:
 *   get:
 *     summary: Get event by id
 *     description: |
 *       Returns a single event with creator name. Non-admin callers
 *       may only view public events or events they themselves
 *       created.
 *     tags:
 *       - Calendar
 *     security:
 *       - bearerAuth: []
 *     parameters:
 *       - in: path
 *         name: id
 *         required: true
 *         schema: { type: integer }
 *     responses:
 *       200:
 *         description: Event detail
 *         content:
 *           application/json:
 *             schema: { type: object }
 *       401: { description: Unauthorized }
 *       403: { description: Access denied }
 *       404: { description: Event not found }
 *       500: { description: Server error }
 *   put:
 *     summary: Update event
 *     description: |
 *       Updates an event. Allowed for the original creator or an
 *       admin. Unspecified fields are left unchanged (`COALESCE`).
 *     tags:
 *       - Calendar
 *     security:
 *       - bearerAuth: []
 *     parameters:
 *       - in: path
 *         name: id
 *         required: true
 *         schema: { type: integer }
 *     requestBody:
 *       required: true
 *       content:
 *         application/json:
 *           schema:
 *             type: object
 *             properties:
 *               title: { type: string }
 *               description: { type: string }
 *               event_date: { type: string, format: date }
 *               end_date: { type: string, format: date }
 *               event_type: { type: string }
 *               venue: { type: string }
 *               is_public: { type: boolean }
 *     responses:
 *       200:
 *         description: Updated event
 *         content:
 *           application/json:
 *             schema: { type: object }
 *       401: { description: Unauthorized }
 *       403: { description: Only creator or admin may update }
 *       404: { description: Event not found }
 *       500: { description: Server error }
 *   delete:
 *     summary: Soft-delete event
 *     description: |
 *       Marks the event as deleted. Allowed for the original
 *       creator or an admin.
 *     tags:
 *       - Calendar
 *     security:
 *       - bearerAuth: []
 *     parameters:
 *       - in: path
 *         name: id
 *         required: true
 *         schema: { type: integer }
 *     responses:
 *       200:
 *         description: Deleted
 *         content:
 *           application/json:
 *             schema: { type: object }
 *       401: { description: Unauthorized }
 *       403: { description: Only creator or admin may delete }
 *       404: { description: Event not found }
 *       500: { description: Server error }
 */
// Get single event
router.get('/:id', auth, (req, res) => {
  try {
    const event = getDb().prepare(`
      SELECT e.*, u.first_name || ' ' || u.last_name as created_by_name
      FROM events e
      LEFT JOIN users u ON e.created_by = u.id
      WHERE e.id = ? AND e.is_deleted = 0
    `).get(req.params.id);
    
    if (!event) {
      return res.status(404).json({ error: 'Event not found' });
    }
    
    // Check access for private events
    if (!event.is_public && event.created_by !== req.user.id && !['school_admin', 'systems_admin'].includes(req.user.role)) {
      return res.status(403).json({ error: 'Access denied' });
    }
    
    res.json(event);
  } catch (error) {
    res.status(500).json({ error: error.message });
  }
});

// Create event
router.post('/', auth, adminOrTeacher, (req, res) => {
  try {
    const { title, description, event_date, end_date, event_type, venue, is_public, academic_year } = req.body;
    
    if (!title || !event_date) {
      return res.status(400).json({ error: 'Title and event_date are required' });
    }
    
    const uid = uuidv4();
    
    const result = getDb().prepare(`
      INSERT INTO events (uid, title, description, event_date, end_date, event_type, venue, is_public, academic_year, created_by, sync_status)
      VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, 'pending')
    `).run(uid, title, description, event_date, end_date, event_type, venue, is_public ? 1 : 0, academic_year, req.user.id);
    
    const event = getDb().prepare('SELECT * FROM events WHERE id = ?').get(result.lastInsertRowid);
    res.status(201).json(event);
  } catch (error) {
    res.status(500).json({ error: error.message });
  }
});

// Update event
router.put('/:id', auth, (req, res) => {
  try {
    const { title, description, event_date, end_date, event_type, venue, is_public } = req.body;
    
    const event = getDb().prepare('SELECT created_by FROM events WHERE id = ?').get(req.params.id);
    
    if (!event) {
      return res.status(404).json({ error: 'Event not found' });
    }
    
    // Only creator or admin can update
    if (event.created_by !== req.user.id && !['school_admin', 'systems_admin'].includes(req.user.role)) {
      return res.status(403).json({ error: 'Only the creator or admin can update this event' });
    }
    
    getDb().prepare(`
      UPDATE events SET
        title = COALESCE(?, title),
        description = COALESCE(?, description),
        event_date = COALESCE(?, event_date),
        end_date = COALESCE(?, end_date),
        event_type = COALESCE(?, event_type),
        venue = COALESCE(?, venue),
        is_public = COALESCE(?, is_public),
        updated_at = CURRENT_TIMESTAMP,
        sync_status = 'pending'
      WHERE id = ? AND is_deleted = 0
    `).run(title, description, event_date, end_date, event_type, venue, is_public, req.params.id);
    
    const updated = getDb().prepare('SELECT * FROM events WHERE id = ?').get(req.params.id);
    res.json(updated);
  } catch (error) {
    res.status(500).json({ error: error.message });
  }
});

// Delete event
router.delete('/:id', auth, (req, res) => {
  try {
    const event = getDb().prepare('SELECT created_by FROM events WHERE id = ?').get(req.params.id);
    
    if (!event) {
      return res.status(404).json({ error: 'Event not found' });
    }
    
    // Only creator or admin can delete
    if (event.created_by !== req.user.id && !['school_admin', 'systems_admin'].includes(req.user.role)) {
      return res.status(403).json({ error: 'Only the creator or admin can delete this event' });
    }
    
    getDb().prepare(`
      UPDATE events SET is_deleted = 1, updated_at = CURRENT_TIMESTAMP, sync_status = 'pending'
      WHERE id = ?
    `).run(req.params.id);
    
    res.json({ success: true, message: 'Event deleted' });
  } catch (error) {
    res.status(500).json({ error: error.message });
  }
});

// ============ EVENT TYPES ============

/**
 * @openapi
 * /api/calendar/types:
 *   get:
 *     summary: List event types (reference)
 *     description: |
 *       Returns the static reference list of calendar event types.
 *       Each entry includes a `value` (machine id), `label`, and
 *       `color` for UI rendering.
 *     tags:
 *       - Calendar
 *     security:
 *       - bearerAuth: []
 *     responses:
 *       200:
 *         description: Event type list
 *         content:
 *           application/json:
 *             schema:
 *               type: array
 *               items:
 *                 type: object
 *                 properties:
 *                   value: { type: string }
 *                   label: { type: string }
 *                   color: { type: string }
 *       401: { description: Unauthorized }
 */
router.get('/types', auth, (req, res) => {
  const types = [
    { value: 'holiday', label: 'Holiday', color: '#10b981' },
    { value: 'exam', label: 'Exam', color: '#ef4444' },
    { value: 'meeting', label: 'Meeting', color: '#3b82f6' },
    { value: 'activity', label: 'Activity', color: '#8b5cf6' },
    { value: 'deadline', label: 'Deadline', color: '#f59e0b' },
    { value: 'other', label: 'Other', color: '#6b7280' }
  ];
  res.json(types);
});

/**
 * @openapi
 * /api/calendar/upcoming:
 *   get:
 *     summary: Upcoming events
 *     description: |
 *       Returns public events (or events the caller created) whose
 *       `event_date` falls between today and today plus `days`
 *       days, ordered ascending and capped at `limit`.
 *     tags:
 *       - Calendar
 *     security:
 *       - bearerAuth: []
 *     parameters:
 *       - in: query
 *         name: days
 *         schema: { type: integer, default: 7 }
 *       - in: query
 *         name: limit
 *         schema: { type: integer, default: 10 }
 *     responses:
 *       200:
 *         description: Upcoming event list
 *         content:
 *           application/json:
 *             schema:
 *               type: array
 *               items: { type: object }
 *       401: { description: Unauthorized }
 *       500: { description: Server error }
 */
// ============ UPCOMING EVENTS ============

router.get('/upcoming', auth, (req, res) => {
  try {
    const { days = 7, limit = 10 } = req.query;
    
    const events = getDb().prepare(`
      SELECT e.*, u.first_name || ' ' || u.last_name as created_by_name
      FROM events e
      LEFT JOIN users u ON e.created_by = u.id
      WHERE e.event_date >= date(\'now\') 
        AND e.event_date <= date(\'now\', '+' || ? || ' days')
        AND e.is_deleted = 0
        AND (e.is_public = 1 OR e.created_by = ?)
      ORDER BY e.event_date ASC, e.title
      LIMIT ?
    `).all(parseInt(days), req.user.id, parseInt(limit));
    
    res.json(events);
  } catch (error) {
    res.status(500).json({ error: error.message });
  }
});

/**
 * @openapi
 * /api/calendar/stats/overview:
 *   get:
 *     summary: Calendar statistics overview
 *     description: |
 *       Returns aggregate counts: total active events, plus
 *       breakdowns by `event_type` (holidays, exams, meetings,
 *       activities) and the count of upcoming events. Also includes
 *       `this_month`, the count of events in the current calendar
 *       month.
 *     tags:
 *       - Calendar
 *     security:
 *       - bearerAuth: []
 *     responses:
 *       200:
 *         description: Aggregate calendar stats
 *         content:
 *           application/json:
 *             schema: { type: object }
 *       401: { description: Unauthorized }
 *       500: { description: Server error }
 */
// ============ CALENDAR STATS ============

router.get('/stats/overview', auth, (req, res) => {
  try {
    const stats = getDb().prepare(`
      SELECT 
        COUNT(*) as total_events,
        SUM(CASE WHEN event_type = 'holiday' THEN 1 ELSE 0 END) as holidays,
        SUM(CASE WHEN event_type = 'exam' THEN 1 ELSE 0 END) as exams,
        SUM(CASE WHEN event_type = 'meeting' THEN 1 ELSE 0 END) as meetings,
        SUM(CASE WHEN event_type = 'activity' THEN 1 ELSE 0 END) as activities,
        SUM(CASE WHEN event_date >= date(\'now\') THEN 1 ELSE 0 END) as upcoming
      FROM events
      WHERE is_deleted = 0
    `).get();
    
    // This month
    const thisMonth = getDb().prepare(`
      SELECT COUNT(*) as count FROM events
      WHERE strftime('%Y', event_date) = strftime('%Y', 'now')
        AND strftime('%m', event_date) = strftime('%m', 'now')
        AND is_deleted = 0
    `).get();
    
    res.json({ ...stats, this_month: thisMonth.count });
  } catch (error) {
    res.status(500).json({ error: error.message });
  }
});

/**
 * @openapi
 * /api/calendar/holidays:
 *   get:
 *     summary: List school holidays
 *     description: |
 *       Returns active events with `event_type = 'holiday'` for the
 *       given year (defaults to the current calendar year),
 *       ordered by `event_date` ascending.
 *     tags:
 *       - Calendar
 *     security:
 *       - bearerAuth: []
 *     parameters:
 *       - in: query
 *         name: year
 *         schema: { type: string }
 *     responses:
 *       200:
 *         description: Holiday list
 *         content:
 *           application/json:
 *             schema:
 *               type: array
 *               items: { type: object }
 *       401: { description: Unauthorized }
 *       500: { description: Server error }
 *   post:
 *     summary: Create school holiday
 *     description: |
 *       Creates a public event with `event_type = 'holiday'`.
 *       Restricted to admin roles.
 *     tags:
 *       - Calendar
 *     security:
 *       - bearerAuth: []
 *     requestBody:
 *       required: true
 *       content:
 *         application/json:
 *           schema:
 *             type: object
 *             required:
 *               - title
 *               - event_date
 *             properties:
 *               title: { type: string }
 *               event_date: { type: string, format: date }
 *               end_date: { type: string, format: date }
 *               description: { type: string }
 *     responses:
 *       201:
 *         description: Created holiday
 *         content:
 *           application/json:
 *             schema: { type: object }
 *       400: { description: Title and event_date are required }
 *       401: { description: Unauthorized }
 *       403: { description: Admin only }
 *       500: { description: Server error }
 */
// ============ HOLIDAYS ============

router.get('/holidays', auth, (req, res) => {
  try {
    const { year } = req.query;
    const currentYear = year || new Date().getFullYear().toString();
    
    const holidays = getDb().prepare(`
      SELECT * FROM events
      WHERE event_type = 'holiday'
        AND strftime('%Y', event_date) = ?
        AND is_deleted = 0
      ORDER BY event_date ASC
    `).all(currentYear);
    
    res.json(holidays);
  } catch (error) {
    res.status(500).json({ error: error.message });
  }
});

// Create holiday
router.post('/holidays', auth, adminOnly, (req, res) => {
  try {
    const { title, event_date, end_date, description } = req.body;
    
    if (!title || !event_date) {
      return res.status(400).json({ error: 'Title and event_date are required' });
    }
    
    const uid = uuidv4();
    
    const result = getDb().prepare(`
      INSERT INTO events (uid, title, description, event_date, end_date, event_type, is_public, created_by, sync_status)
      VALUES (?, ?, ?, ?, ?, 'holiday', 1, ?, 'pending')
    `).run(uid, title, description, event_date, end_date, req.user.id);
    
    const holiday = getDb().prepare('SELECT * FROM events WHERE id = ?').get(result.lastInsertRowid);
    res.status(201).json(holiday);
  } catch (error) {
    res.status(500).json({ error: error.message });
  }
});

/**
 * @openapi
 * /api/calendar/academic-calendar:
 *   get:
 *     summary: Academic calendar (term + holiday grid)
 *     description: |
 *       Returns events whose `academic_year` matches the given year
 *       (defaults to the current calendar year), grouped into a
 *       `{ [YYYY-MM]: events[] }` map by month. The response also
 *       includes the resolved `academic_year` and a `total` count.
 *     tags:
 *       - Calendar
 *     security:
 *       - bearerAuth: []
 *     parameters:
 *       - in: query
 *         name: academic_year
 *         schema: { type: string }
 *     responses:
 *       200:
 *         description: Academic calendar grid
 *         content:
 *           application/json:
 *             schema: { type: object }
 *       401: { description: Unauthorized }
 *       500: { description: Server error }
 */
// ============ ACADEMIC CALENDAR ============

router.get('/academic-calendar', auth, (req, res) => {
  try {
    const { academic_year } = req.query;
    
    let query = `
      SELECT * FROM events
      WHERE academic_year = ? AND is_deleted = 0
      ORDER BY event_date ASC
    `;
    
    const events = getDb().prepare(query).all(academic_year || new Date().getFullYear().toString());
    
    // Group by month
    const byMonth = events.reduce((acc, event) => {
      const month = event.event_date.substring(0, 7);
      if (!acc[month]) acc[month] = [];
      acc[month].push(event);
      return acc;
    }, {});
    
    res.json({
      academic_year: academic_year || new Date().getFullYear().toString(),
      months: byMonth,
      total: events.length
    });
  } catch (error) {
    res.status(500).json({ error: error.message });
  }
});

module.exports = router;