/**
 * Edutainment Content & Games Controller
 *
 * Routes:
 *   GET    /api/edutainment/content          - list pool content
 *   POST   /api/edutainment/content          - create pool content
 *   DELETE /api/edutainment/content/:id      - delete pool content
 *
 *   GET    /api/edutainment/games            - list custom puzzles/games
 *   POST   /api/edutainment/games            - create custom puzzle/game
 *   DELETE /api/edutainment/games/:id        - delete custom puzzle/game
 *   POST   /api/edutainment/sessions         - save student game session / score
 */

'use strict';

const express = require('express');
const router = express.Router();
const path = require('path');
const Database = require('better-sqlite3');
const { v4: uuidv4 } = require('uuid');

const dbPath = process.env.DB_PATH || path.join(__dirname, '../../data/school.db');
const db = new Database(dbPath);
db.pragma('foreign_keys = ON');

// 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 {
    req.user = require('jsonwebtoken').verify(
      token,
      require('../config').jwtSecret
    );
    next();
  } catch (err) {
    res.status(401).json({ error: 'Invalid token' });
  }
};

const TEACHER_ROLES = ['teacher', 'school_admin', 'systems_admin', 'principal', 'clubs_head'];
const ADMIN_ROLES = ['school_admin', 'systems_admin', 'principal'];

const isOwnerOrAdmin = (content, user) => {
  if (!content || !user) return false;
  if (ADMIN_ROLES.includes(user.role)) return true;
  return content.created_by === user.id;
};

// ==================== POOL CONTENT ENDPOINTS ====================

// GET: List content
/**
 * @openapi
 * /api/edutainment/content:
 *   get:
 *     summary: List edutainment content pool
 *     description: |
 *       Returns active pool content (scramble words or trivia
 *       questions) joined with the subject name and creator
 *       name. For trivia rows, `options` is parsed back to an
 *       array. Optional filters: `game_type` (`scramble` |
 *       `trivia`), `subject_id`.
 *     tags:
 *       - Edutainment
 *     security:
 *       - bearerAuth: []
 *     parameters:
 *       - in: query
 *         name: game_type
 *         schema:
 *           type: string
 *           enum: [scramble, trivia]
 *       - in: query
 *         name: subject_id
 *         schema: { type: integer }
 *     responses:
 *       200:
 *         description: Content list
 *         content:
 *           application/json:
 *             schema:
 *               type: array
 *               items: { type: object }
 *       401: { description: Unauthorized }
 *       500: { description: Server error }
 */
router.get('/content', auth, (req, res) => {
  const { game_type, subject_id } = req.query;

  let query = 'SELECT ec.*, s.name as subject_name, u.first_name, u.last_name FROM edutainment_content ec LEFT JOIN subjects_new s ON ec.subject_id = s.id LEFT JOIN users u ON ec.created_by = u.id WHERE ec.is_deleted = 0';
  const params = [];

  if (game_type) {
    query += ' AND ec.game_type = ?';
    params.push(game_type);
  }
  if (subject_id) {
    query += ' AND ec.subject_id = ?';
    params.push(Number(subject_id));
  }

  query += ' ORDER BY ec.created_at DESC';

  try {
    const list = db.prepare(query).all(...params);
    const formatted = list.map(item => {
      if (item.game_type === 'trivia' && item.options) {
        try {
          item.options = JSON.parse(item.options);
        } catch (e) {
          item.options = [];
        }
      }
      return item;
    });
    res.json(formatted);
  } catch (e) {
    res.status(500).json({ error: 'Failed to fetch content: ' + e.message });
  }
});

// POST: Create content
/**
 * @openapi
 * /api/edutainment/content:
 *   post:
 *     summary: Create edutainment content
 *     description: |
 *       Adds a pool item to the catalog. For `scramble`, the
 *       answer is derived by stripping non-letters from the
 *       question text and uppercasing it. For `trivia`, an
 *       `options` array (>= 2 entries) is required and the
 *       `correct_answer` must match one of them. Restricted to
 *       `teacher`, `school_admin`, `systems_admin`,
 *       `principal`, and `clubs_head`.
 *     tags:
 *       - Edutainment
 *     security:
 *       - bearerAuth: []
 *     requestBody:
 *       required: true
 *       content:
 *         application/json:
 *           schema:
 *             type: object
 *             required:
 *               - game_type
 *               - subject_id
 *               - question_text
 *             properties:
 *               game_type:
 *                 type: string
 *                 enum: [scramble, trivia]
 *               subject_id: { type: integer }
 *               question_text: { type: string }
 *               hint_text: { type: string }
 *               options:
 *                 type: array
 *                 items: { type: string }
 *                 description: Required for trivia (>= 2 entries).
 *               correct_answer: { type: string }
 *     responses:
 *       201:
 *         description: Created content
 *         content:
 *           application/json:
 *             schema: { type: object }
 *       400: { description: Validation error }
 *       401: { description: Unauthorized }
 *       403: { description: Teacher or admin only }
 *       500: { description: Server error }
 */
router.post('/content', auth, (req, res) => {
  if (!TEACHER_ROLES.includes(req.user.role)) {
    return res.status(403).json({ error: 'Only teachers and administrators can add game content' });
  }

  const { game_type, subject_id, question_text, hint_text, options, correct_answer } = req.body;

  if (!game_type || !['scramble', 'trivia'].includes(game_type)) {
    return res.status(400).json({ error: "game_type must be 'scramble' or 'trivia'" });
  }
  if (!subject_id) {
    return res.status(400).json({ error: 'subject_id is required' });
  }
  if (!question_text || typeof question_text !== 'string' || !question_text.trim()) {
    return res.status(400).json({ error: 'question_text is required' });
  }

  let finalOptions = null;
  let finalCorrectAnswer = correct_answer;

  if (game_type === 'scramble') {
    finalCorrectAnswer = question_text.trim().toUpperCase().replace(/[^A-Z]/g, '');
    if (finalCorrectAnswer.length < 2) {
      return res.status(400).json({ error: 'Word must be at least 2 letters long' });
    }
  } else if (game_type === 'trivia') {
    if (!Array.isArray(options) || options.length < 2) {
      return res.status(400).json({ error: 'Trivia question must have at least 2 options' });
    }
    if (!correct_answer || !options.includes(correct_answer)) {
      return res.status(400).json({ error: 'correct_answer must match one of the options' });
    }
    finalOptions = JSON.stringify(options);
  }

  const uid = uuidv4();

  try {
    const result = db.prepare(`
      INSERT INTO edutainment_content (
        uid, game_type, subject_id, created_by,
        question_text, hint_text, options, correct_answer
      )
      VALUES (?, ?, ?, ?, ?, ?, ?, ?)
    `).run(
      uid,
      game_type,
      Number(subject_id),
      req.user.id,
      game_type === 'scramble' ? finalCorrectAnswer : question_text.trim(),
      hint_text ? hint_text.trim() : null,
      finalOptions,
      finalCorrectAnswer
    );

    const created = db.prepare('SELECT * FROM edutainment_content WHERE id = ?').get(result.lastInsertRowid);
    if (created && created.options) {
      created.options = JSON.parse(created.options);
    }
    res.status(201).json(created);
  } catch (e) {
    res.status(500).json({ error: 'Failed to create content: ' + e.message });
  }
});

// DELETE: Delete content
/**
 * @openapi
 * /api/edutainment/content/{id}:
 *   delete:
 *     summary: Soft-delete edutainment content
 *     description: |
 *       Marks the pool content as deleted. Owner or admin only.
 *     tags:
 *       - Edutainment
 *     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: Owner or admin only }
 *       404: { description: Content not found }
 *       500: { description: Server error }
 */
router.delete('/content/:id', auth, (req, res) => {
  try {
    const content = db.prepare('SELECT * FROM edutainment_content WHERE id = ? AND is_deleted = 0').get(req.params.id);
    if (!content) {
      return res.status(404).json({ error: 'Content not found' });
    }
    if (!isOwnerOrAdmin(content, req.user)) {
      return res.status(403).json({ error: 'Unauthorized to delete this content' });
    }
    db.prepare('UPDATE edutainment_content SET is_deleted = 1, updated_at = CURRENT_TIMESTAMP WHERE id = ?').run(req.params.id);
    res.json({ success: true });
  } catch (e) {
    res.status(500).json({ error: 'Failed to delete content: ' + e.message });
  }
});

// ==================== CUSTOM PUZZLES / GAMES ENDPOINTS ====================

// GET: List custom games
/**
 * @openapi
 * /api/edutainment/games:
 *   get:
 *     summary: List edutainment games
 *     description: |
 *       Returns active custom puzzles/games joined with the
 *       subject name and creator name, plus an
 *       `attempts_count` for the calling user. Students only
 *       see published games. `game_config` is parsed back to
 *       an object on the response. Optional filters:
 *       `game_type` (`math` | `scramble` | `trivia`),
 *       `subject_id`.
 *     tags:
 *       - Edutainment
 *     security:
 *       - bearerAuth: []
 *     parameters:
 *       - in: query
 *         name: game_type
 *         schema:
 *           type: string
 *           enum: [math, scramble, trivia]
 *       - in: query
 *         name: subject_id
 *         schema: { type: integer }
 *     responses:
 *       200:
 *         description: Game list
 *         content:
 *           application/json:
 *             schema:
 *               type: array
 *               items: { type: object }
 *       401: { description: Unauthorized }
 *       500: { description: Server error }
 */
router.get('/games', auth, (req, res) => {
  const { game_type, subject_id } = req.query;

  let query = `
    SELECT eg.*, s.name as subject_name, u.first_name, u.last_name,
      (SELECT COUNT(*) FROM edutainment_sessions WHERE game_id = eg.id AND student_id = ?) as attempts_count
    FROM edutainment_games eg
    LEFT JOIN subjects_new s ON eg.subject_id = s.id
    LEFT JOIN users u ON eg.created_by = u.id
    WHERE eg.is_deleted = 0
  `;
  const params = [req.user.id];

  if (req.user.role === 'student') {
    query += ' AND eg.is_published = 1';
  }
  if (game_type) {
    query += ' AND eg.game_type = ?';
    params.push(game_type);
  }
  if (subject_id) {
    query += ' AND eg.subject_id = ?';
    params.push(Number(subject_id));
  }

  query += ' ORDER BY eg.created_at DESC';

  try {
    const list = db.prepare(query).all(...params);
    const formatted = list.map(game => {
      try {
        game.game_config = JSON.parse(game.game_config);
      } catch (e) {
        game.game_config = {};
      }
      return game;
    });
    res.json(formatted);
  } catch (e) {
    res.status(500).json({ error: 'Failed to fetch games: ' + e.message });
  }
});

// POST: Create custom game
/**
 * @openapi
 * /api/edutainment/games:
 *   post:
 *     summary: Create edutainment game
 *     description: |
 *       Creates a custom puzzle/game (`math`, `scramble`, or
 *       `trivia`) published immediately (`is_published = 1`).
 *       `game_config` must be an object and is persisted as a
 *       JSON string. Restricted to `teacher`,
 *       `school_admin`, `systems_admin`, `principal`, and
 *       `clubs_head`.
 *     tags:
 *       - Edutainment
 *     security:
 *       - bearerAuth: []
 *     requestBody:
 *       required: true
 *       content:
 *         application/json:
 *           schema:
 *             type: object
 *             required:
 *               - game_type
 *               - title
 *               - subject_id
 *               - game_config
 *             properties:
 *               game_type:
 *                 type: string
 *                 enum: [math, scramble, trivia]
 *               title: { type: string }
 *               description: { type: string }
 *               subject_id: { type: integer }
 *               difficulty:
 *                 type: string
 *                 description: Defaults to `medium`.
 *               reward_points:
 *                 type: integer
 *                 description: Defaults to 10.
 *               time_limit_seconds:
 *                 type: integer
 *                 description: Defaults to 60.
 *               game_config: { type: object }
 *     responses:
 *       201:
 *         description: Created game
 *         content:
 *           application/json:
 *             schema: { type: object }
 *       400: { description: Validation error }
 *       401: { description: Unauthorized }
 *       403: { description: Teacher or admin only }
 *       500: { description: Server error }
 */
router.post('/games', auth, (req, res) => {
  if (!TEACHER_ROLES.includes(req.user.role)) {
    return res.status(403).json({ error: 'Only teachers and administrators can create puzzles' });
  }

  const { game_type, title, description, subject_id, difficulty, reward_points, time_limit_seconds, game_config } = req.body;

  if (!game_type || !['math', 'scramble', 'trivia'].includes(game_type)) {
    return res.status(400).json({ error: 'Invalid game_type' });
  }
  if (!title || !title.trim()) {
    return res.status(400).json({ error: 'Title is required' });
  }
  if (!subject_id) {
    return res.status(400).json({ error: 'Subject is required' });
  }
  if (!game_config || typeof game_config !== 'object') {
    return res.status(400).json({ error: 'Game configuration is required' });
  }

  const uid = uuidv4();

  try {
    const result = db.prepare(`
      INSERT INTO edutainment_games (
        uid, game_type, title, description, subject_id,
        created_by, difficulty, reward_points, time_limit_seconds,
        game_config, is_published
      )
      VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, 1)
    `).run(
      uid,
      game_type,
      title.trim(),
      description ? description.trim() : null,
      Number(subject_id),
      req.user.id,
      difficulty || 'medium',
      Number(reward_points) || 10,
      Number(time_limit_seconds) || 60,
      JSON.stringify(game_config)
    );

    const created = db.prepare('SELECT * FROM edutainment_games WHERE id = ?').get(result.lastInsertRowid);
    created.game_config = JSON.parse(created.game_config);
    res.status(201).json(created);
  } catch (e) {
    res.status(500).json({ error: 'Failed to create game: ' + e.message });
  }
});

// DELETE: Delete custom game
/**
 * @openapi
 * /api/edutainment/games/{id}:
 *   delete:
 *     summary: Soft-delete edutainment game
 *     description: |
 *       Marks the custom game as deleted. Owner or admin only.
 *     tags:
 *       - Edutainment
 *     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: Owner or admin only }
 *       404: { description: Game not found }
 *       500: { description: Server error }
 */
router.delete('/games/:id', auth, (req, res) => {
  try {
    const game = db.prepare('SELECT * FROM edutainment_games WHERE id = ? AND is_deleted = 0').get(req.params.id);
    if (!game) {
      return res.status(404).json({ error: 'Game not found' });
    }
    if (!isOwnerOrAdmin(game, req.user)) {
      return res.status(403).json({ error: 'Unauthorized to delete this game' });
    }
    db.prepare('UPDATE edutainment_games SET is_deleted = 1, updated_at = CURRENT_TIMESTAMP WHERE id = ?').run(req.params.id);
    res.json({ success: true });
  } catch (e) {
    res.status(500).json({ error: 'Failed to delete game: ' + e.message });
  }
});

// POST: Save student session & score
/**
 * @openapi
 * /api/edutainment/sessions:
 *   post:
 *     summary: Submit edutainment game attempt
 *     description: |
 *       Records a completed student game session for the given
 *       game. The student's `score` (0-100) is stored, and
 *       `points_earned` is awarded in full when the score is
 *       at least 60 (otherwise 0). Returns the created session.
 *       Restricted to the `student` role.
 *     tags:
 *       - Edutainment
 *     security:
 *       - bearerAuth: []
 *     requestBody:
 *       required: true
 *       content:
 *         application/json:
 *           schema:
 *             type: object
 *             required:
 *               - game_id
 *               - score
 *             properties:
 *               game_id: { type: integer }
 *               score:
 *                 type: number
 *                 format: float
 *                 minimum: 0
 *                 maximum: 100
 *     responses:
 *       201:
 *         description: Created session
 *         content:
 *           application/json:
 *             schema: { type: object }
 *       400: { description: game_id is required }
 *       401: { description: Unauthorized }
 *       403: { description: Student only }
 *       404: { description: Game not found }
 *       500: { description: Server error }
 */
router.post('/sessions', auth, (req, res) => {
  if (req.user.role !== 'student') {
    return res.status(403).json({ error: 'Only students can submit game attempts' });
  }

  const { game_id, score } = req.body;

  if (!game_id) {
    return res.status(400).json({ error: 'game_id is required' });
  }

  try {
    const game = db.prepare('SELECT * FROM edutainment_games WHERE id = ? AND is_deleted = 0').get(game_id);
    if (!game) {
      return res.status(404).json({ error: 'Game/Puzzle not found' });
    }

    const uid = uuidv4();
    const pointsEarned = Number(score) >= 60 ? (game.reward_points || 10) : 0; // earn points if student gets >= 60 score

    const result = db.prepare(`
      INSERT INTO edutainment_sessions (
        uid, game_id, student_id, score,
        completed_at, points_earned
      )
      VALUES (?, ?, ?, ?, CURRENT_TIMESTAMP, ?)
    `).run(
      uid,
      Number(game_id),
      req.user.id,
      Number(score),
      pointsEarned
    );

    const created = db.prepare('SELECT * FROM edutainment_sessions WHERE id = ?').get(result.lastInsertRowid);
    res.status(201).json(created);
  } catch (e) {
    res.status(500).json({ error: 'Failed to save session: ' + e.message });
  }
});

module.exports = router;
