/**
 * Grades Controller
 * Student grade management and reporting
 */

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 JWT_SECRET = process.env.JWT_SECRET || 'africa-alert-secret-key-2024';
    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 (req.user.role !== 'admin' && 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 (req.user.role !== 'admin') {
    return res.status(403).json({ error: 'Admin access required' });
  }
  next();
};

// Calculate grade from percentage
const calculateGrade = (percentage) => {
  if (percentage >= 90) return 'A+';
  if (percentage >= 85) return 'A';
  if (percentage >= 80) return 'A-';
  if (percentage >= 75) return 'B+';
  if (percentage >= 70) return 'B';
  if (percentage >= 65) return 'B-';
  if (percentage >= 60) return 'C+';
  if (percentage >= 55) return 'C';
  if (percentage >= 50) return 'C-';
  if (percentage >= 45) return 'D';
  return 'F';
};

// ============ GRADES CRUD ============

// List grades
router.get('/', auth, (req, res) => {
  try {
    const { student_id, subject_id, class_id, exam_type, academic_year, term } = req.query;
    
    let query = `
      SELECT g.*, 
        u.first_name || ' ' || u.last_name as student_name,
        s.name as subject_name,
        c.name as class_name,
        t.first_name || ' ' || t.last_name as graded_by_name
      FROM grades g
      JOIN users u ON g.student_id = u.id
      JOIN subjects s ON g.subject_id = s.id
      LEFT JOIN classes c ON s.class_id = c.id
      LEFT JOIN users t ON g.graded_by = t.id
      WHERE g.is_deleted = 0
    `;
    const params = [];
    
    // Students can only see their own grades
    if (req.user.role === 'student') {
      query += ' AND g.student_id = ?';
      params.push(req.user.id);
    } else if (req.user.role === 'parent') {
      // Parents can see their children's grades
      query += ' AND g.student_id IN (SELECT id FROM users WHERE is_deleted = 0 AND (id IN (SELECT student_id FROM enrollments WHERE is_deleted = 0) OR 1=0))';
    } else {
      if (student_id) {
        query += ' AND g.student_id = ?';
        params.push(student_id);
      }
    }
    
    if (subject_id) {
      query += ' AND g.subject_id = ?';
      params.push(subject_id);
    }
    if (class_id) {
      query += ' AND s.class_id = ?';
      params.push(class_id);
    }
    if (exam_type) {
      query += ' AND g.exam_type = ?';
      params.push(exam_type);
    }
    if (academic_year) {
      query += ' AND g.academic_year = ?';
      params.push(academic_year);
    }
    if (term) {
      query += ' AND g.term = ?';
      params.push(term);
    }
    
    query += ' ORDER BY g.graded_at DESC';
    
    const grades = getDb().prepare(query).all(...params);
    res.json(grades);
  } catch (error) {
    res.status(500).json({ error: error.message });
  }
});

// Get single grade
router.get('/:id', auth, (req, res) => {
  try {
    const grade = getDb().prepare(`
      SELECT g.*, 
        u.first_name || ' ' || u.last_name as student_name,
        s.name as subject_name,
        c.name as class_name,
        t.first_name || ' ' || t.last_name as graded_by_name
      FROM grades g
      JOIN users u ON g.student_id = u.id
      JOIN subjects s ON g.subject_id = s.id
      LEFT JOIN classes c ON s.class_id = c.id
      LEFT JOIN users t ON g.graded_by = t.id
      WHERE g.id = ? AND g.is_deleted = 0
    `).get(req.params.id);
    
    if (!grade) {
      return res.status(404).json({ error: 'Grade not found' });
    }
    
    // Students can only see their own grades
    if (req.user.role === 'student' && grade.student_id !== req.user.id) {
      return res.status(403).json({ error: 'Access denied' });
    }
    
    res.json(grade);
  } catch (error) {
    res.status(500).json({ error: error.message });
  }
});

// Create grade
router.post('/', auth, adminOrTeacher, (req, res) => {
  try {
    const { student_id, subject_id, exam_type, marks, total_marks, remarks, academic_year, term } = req.body;
    
    if (!student_id || !subject_id || !exam_type || marks === undefined) {
      return res.status(400).json({ error: 'student_id, subject_id, exam_type, and marks are required' });
    }
    
    const percentage = total_marks ? (marks / total_marks) * 100 : marks;
    const grade = calculateGrade(percentage);
    const uid = uuidv4();
    
    const result = getDb().prepare(`
      INSERT INTO grades (uid, student_id, subject_id, exam_type, marks, total_marks, grade, remarks, graded_by, academic_year, term)
      VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
    `).run(uid, student_id, subject_id, exam_type, marks, total_marks || 100, grade, remarks, req.user.id, academic_year, term);
    
    const newGrade = getDb().prepare(`
      SELECT g.*, u.first_name || ' ' || u.last_name as student_name, s.name as subject_name
      FROM grades g
      JOIN users u ON g.student_id = u.id
      JOIN subjects s ON g.subject_id = s.id
      WHERE g.id = ?
    `).get(result.lastInsertRowid);
    
    res.status(201).json(newGrade);
  } catch (error) {
    res.status(500).json({ error: error.message });
  }
});

// Bulk create grades
router.post('/bulk', auth, adminOrTeacher, (req, res) => {
  try {
    const { grades } = req.body;
    
    if (!Array.isArray(grades) || grades.length === 0) {
      return res.status(400).json({ error: 'Grades array required' });
    }
    
    const insert = getDb().prepare(`
      INSERT INTO grades (uid, student_id, subject_id, exam_type, marks, total_marks, grade, remarks, graded_by, academic_year, term)
      VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
    `);
    
    const insertMany = getDb().transaction((grades) => {
      const results = [];
      for (const g of grades) {
        const percentage = g.total_marks ? (g.marks / g.total_marks) * 100 : g.marks;
        const grade = calculateGrade(percentage);
        const uid = uuidv4();
        
        try {
          insert.run(uid, g.student_id, g.subject_id, g.exam_type, g.marks, g.total_marks || 100, grade, g.remarks, req.user.id, g.academic_year, g.term);
          results.push({ student_id: g.student_id, subject_id: g.subject_id, success: true });
        } catch (e) {
          results.push({ student_id: g.student_id, error: e.message, success: false });
        }
      }
      return results;
    });
    
    const results = insertMany(grades);
    
    res.status(201).json({
      created: results.filter(r => r.success).length,
      failed: results.filter(r => !r.success).length,
      results
    });
  } catch (error) {
    res.status(500).json({ error: error.message });
  }
});

// Update grade
router.put('/:id', auth, adminOrTeacher, (req, res) => {
  try {
    const { marks, remarks } = req.body;
    
    if (marks === undefined) {
      return res.status(400).json({ error: 'Marks is required' });
    }
    
    const existing = getDb().prepare('SELECT * FROM grades WHERE id = ?').get(req.params.id);
    if (!existing) {
      return res.status(404).json({ error: 'Grade not found' });
    }
    
    const totalMarks = existing.total_marks;
    const percentage = (marks / totalMarks) * 100;
    const grade = calculateGrade(percentage);
    
    getDb().prepare(`
      UPDATE grades SET
        marks = ?,
        grade = ?,
        remarks = COALESCE(?, remarks),
        graded_by = ?,
        graded_at = CURRENT_TIMESTAMP,
        updated_at = CURRENT_TIMESTAMP,
        sync_status = 'pending'
      WHERE id = ? AND is_deleted = 0
    `).run(marks, grade, remarks, req.user.id, req.params.id);
    
    const updated = getDb().prepare(`
      SELECT g.*, u.first_name || ' ' || u.last_name as student_name, s.name as subject_name
      FROM grades g
      JOIN users u ON g.student_id = u.id
      JOIN subjects s ON g.subject_id = s.id
      WHERE g.id = ?
    `).get(req.params.id);
    
    res.json(updated);
  } catch (error) {
    res.status(500).json({ error: error.message });
  }
});

// Delete grade
router.delete('/:id', auth, adminOnly, (req, res) => {
  try {
    getDb().prepare(`
      UPDATE grades SET is_deleted = 1, updated_at = CURRENT_TIMESTAMP, sync_status = 'pending'
      WHERE id = ?
    `).run(req.params.id);
    
    res.json({ success: true, message: 'Grade deleted' });
  } catch (error) {
    res.status(500).json({ error: error.message });
  }
});

// ============ STUDENT PROGRESS ============

// Get student's grade summary
router.get('/students/:studentId/summary', auth, (req, res) => {
  try {
    const studentId = parseInt(req.params.studentId);
    
    // Check access
    if (req.user.role === 'student' && req.user.id !== studentId) {
      return res.status(403).json({ error: 'Access denied' });
    }
    
    // Overall stats
    const overall = getDb().prepare(`
      SELECT 
        COUNT(*) as total_grades,
        AVG(marks / total_marks * 100) as average_percentage,
        MIN(marks / total_marks * 100) as lowest_percentage,
        MAX(marks / total_marks * 100) as highest_percentage
      FROM grades
      WHERE student_id = ? AND is_deleted = 0 AND total_marks > 0
    `).get(studentId);
    
    // By subject
    const bySubject = getDb().prepare(`
      SELECT s.id, s.name,
        COUNT(*) as exam_count,
        AVG(g.marks / g.total_marks * 100) as average_percentage,
        MIN(g.marks / g.total_marks * 100) as lowest,
        MAX(g.marks / g.total_marks * 100) as highest
      FROM grades g
      JOIN subjects s ON g.subject_id = s.id
      WHERE g.student_id = ? AND g.is_deleted = 0 AND g.total_marks > 0
      GROUP BY s.id
      ORDER BY average_percentage DESC
    `).all(studentId);
    
    // By exam type
    const byType = getDb().prepare(`
      SELECT exam_type,
        COUNT(*) as count,
        AVG(marks / total_marks * 100) as average_percentage
      FROM grades
      WHERE student_id = ? AND is_deleted = 0 AND total_marks > 0
      GROUP BY exam_type
    `).all(studentId);
    
    // Recent grades
    const recent = getDb().prepare(`
      SELECT g.*, s.name as subject_name
      FROM grades g
      JOIN subjects s ON g.subject_id = s.id
      WHERE g.student_id = ? AND g.is_deleted = 0
      ORDER BY g.graded_at DESC
      LIMIT 10
    `).all(studentId);
    
    res.json({
      overall,
      by_subject: bySubject,
      by_exam_type: byType,
      recent_grades: recent
    });
  } catch (error) {
    res.status(500).json({ error: error.message });
  }
});

// ============ CLASS ANALYTICS ============

// Get class performance
router.get('/class/:classId/performance', auth, adminOrTeacher, (req, res) => {
  try {
    const { subject_id, exam_type } = req.query;
    
    let query = `
      SELECT 
        u.id,
        u.first_name,
        u.last_name,
        COUNT(g.id) as total_exams,
        AVG(g.marks / g.total_marks * 100) as average_percentage,
        MIN(g.marks / g.total_marks * 100) as lowest,
        MAX(g.marks / g.total_marks * 100) as highest
      FROM grades g
      JOIN users u ON g.student_id = u.id
      JOIN subjects s ON g.subject_id = s.id
      WHERE s.class_id = ? AND g.is_deleted = 0 AND g.total_marks > 0
    `;
    const params = [req.params.classId];
    
    if (subject_id) {
      query += ' AND g.subject_id = ?';
      params.push(subject_id);
    }
    if (exam_type) {
      query += ' AND g.exam_type = ?';
      params.push(exam_type);
    }
    
    query += ' GROUP BY u.id ORDER BY average_percentage DESC';
    
    const students = getDb().prepare(query).all(...params);
    res.json(students);
  } catch (error) {
    res.status(500).json({ error: error.message });
  }
});

// ============ MY GRADES (Student) ============

router.get('/my/grades', auth, (req, res) => {
  try {
    const { subject_id, academic_year, term } = req.query;
    
    let query = `
      SELECT g.*, s.name as subject_name, s.code as subject_code
      FROM grades g
      JOIN subjects s ON g.subject_id = s.id
      WHERE g.student_id = ? AND g.is_deleted = 0
    `;
    const params = [req.user.id];
    
    if (subject_id) {
      query += ' AND g.subject_id = ?';
      params.push(subject_id);
    }
    if (academic_year) {
      query += ' AND g.academic_year = ?';
      params.push(academic_year);
    }
    if (term) {
      query += ' AND g.term = ?';
      params.push(term);
    }
    
    query += ' ORDER BY g.graded_at DESC';
    
    const grades = getDb().prepare(query).all(...params);
    
    // Calculate summary
    const summary = {
      total: grades.length,
      average: grades.length > 0 
        ? grades.reduce((sum, g) => sum + (g.marks / g.total_marks * 100), 0) / grades.length 
        : 0
    };
    
    res.json({ grades, summary });
  } catch (error) {
    res.status(500).json({ error: error.message });
  }
});

module.exports = router;