const db   = require('../db/db');
const path = require('path');
const fs   = require('fs');
const { pushNotif, pushParentNotif } = require('../utils/notifications');
const { UPLOADS_DIR } = require('../config');
const { checkMagicBytes } = require('../utils/magic');

/* ── POST /api/submissions  (student) ─────────────────────────────────── */
function submit(req, res) {
  if (!req.file) return res.status(400).json({ error: 'No file uploaded' });
  const { assignment_id, class_id, message } = req.body;
  const student_id = req.user.id;

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

  const member = db.prepare(
    'SELECT 1 FROM class_members WHERE class_id = ? AND user_id = ?'
  ).get(Number(class_id), student_id);
  if (!member) return res.status(403).json({ error: 'Not a member of this class' });

  if (assignment_id) {
    const assign = db.prepare(
      'SELECT id FROM assignments WHERE id = ? AND class_id = ?'
    ).get(Number(assignment_id), Number(class_id));
    if (!assign) return res.status(400).json({ error: 'Assignment not found in class' });
  }

  // Magic bytes verification — reject spoofed MIME types
  const uploadedPath = path.resolve(UPLOADS_DIR, req.file.filename);
  if (!checkMagicBytes(uploadedPath, req.file.mimetype)) {
    try { fs.unlinkSync(uploadedPath); } catch {}
    return res.status(400).json({ error: 'Содержимое файла не соответствует его расширению' });
  }

  let r;
  try {
    r = db.prepare(`
      INSERT INTO submissions
        (class_id, assignment_id, student_id, original_name, stored_name, mimetype, size, message)
      VALUES (?, ?, ?, ?, ?, ?, ?, ?)
    `).run(
      Number(class_id),
      assignment_id ? Number(assignment_id) : null,
      student_id,
      req.file.originalname,
      req.file.filename,
      req.file.mimetype,
      req.file.size,
      message?.trim() || null
    );
  } catch (err) {
    const fp = path.resolve(UPLOADS_DIR, req.file.filename);
    if (fp.startsWith(UPLOADS_DIR + path.sep)) { try { fs.unlinkSync(fp); } catch {} }
    throw err;
  }

  // Notify teacher that a student submitted work
  try {
    const cls = db.prepare('SELECT teacher_id, name FROM classes WHERE id = ?').get(Number(class_id));
    if (cls?.teacher_id) {
      const assignTitle = assignment_id
        ? db.prepare('SELECT title FROM assignments WHERE id = ?').get(Number(assignment_id))?.title
        : null;
      const studentName = req.user.name || req.user.email;
      const msg = assignTitle
        ? `«${studentName}» сдал работу по заданию «${assignTitle}»`
        : `«${studentName}» прикрепил работу в классе «${cls.name}»`;
      pushNotif(cls.teacher_id, 'submission', msg, '/classes');
    }
  } catch (e) { console.error('[submissions] notify teacher:', e.message); }

  res.status(201).json({ id: r.lastInsertRowid });
}

/* ── GET /api/submissions/my  (student) ───────────────────────────────── */
function getMySubmissions(req, res) {
  const rows = db.prepare(`
    SELECT s.id, s.class_id, s.assignment_id, s.original_name, s.size,
           s.mimetype, s.message, s.status, s.teacher_note, s.grade, s.submitted_at,
           a.title AS assignment_title
    FROM submissions s
    LEFT JOIN assignments a ON a.id = s.assignment_id
    WHERE s.student_id = ?
    ORDER BY s.submitted_at DESC
  `).all(req.user.id);
  res.json(rows);
}

/* ── GET /api/submissions?class_id=X  (teacher/admin) ─────────────────── */
function getClassSubmissions(req, res) {
  const { class_id } = req.query;
  if (!class_id) return res.status(400).json({ error: 'class_id required' });

  if (req.user.role === 'teacher') {
    const cls = db.prepare('SELECT teacher_id FROM classes WHERE id = ?').get(Number(class_id));
    if (!cls) return res.status(404).json({ error: 'Class not found' });
    if (cls.teacher_id !== req.user.id)
      return res.status(403).json({ error: 'Forbidden' });
  }

  const rows = db.prepare(`
    SELECT s.id, s.class_id, s.assignment_id, s.original_name, s.size,
           s.mimetype, s.message, s.status, s.teacher_note, s.grade, s.submitted_at,
           u.name AS student_name, u.email AS student_email,
           a.title AS assignment_title
    FROM submissions s
    JOIN  users u ON u.id = s.student_id
    LEFT JOIN assignments a ON a.id = s.assignment_id
    WHERE s.class_id = ?
    ORDER BY s.submitted_at DESC
  `).all(Number(class_id));

  res.json(rows);
}

/* ── PATCH /api/submissions/:id  (teacher/admin) ──────────────────────── */
function reviewSubmission(req, res) {
  const sub = db.prepare(`
    SELECT s.*, c.teacher_id FROM submissions s
    JOIN classes c ON c.id = s.class_id WHERE s.id = ?
  `).get(Number(req.params.id));
  if (!sub) return res.status(404).json({ error: 'Submission not found' });

  if (req.user.role === 'teacher' && sub.teacher_id !== req.user.id)
    return res.status(403).json({ error: 'Forbidden' });

  const VALID_STATUSES = ['new', 'reviewed', 'revision', 'resubmitted', 'accepted'];
  const { status, teacher_note, grade } = req.body;
  if (status && !VALID_STATUSES.includes(status))
    return res.status(400).json({ error: 'Invalid status' });
  if (grade !== undefined && grade !== null) {
    const g = Number(grade);
    if (!Number.isInteger(g) || g < 0 || g > 100)
      return res.status(400).json({ error: 'Grade must be integer 0-100' });
  }

  const gradeVal = grade === undefined ? sub.grade :
                   (grade === null || grade === '') ? null : Number(grade);
  const noteVal  = teacher_note !== undefined ? (teacher_note?.trim() || null) : sub.teacher_note;
  const statusVal = status || sub.status;
  const reviewedAt = (status === 'reviewed' || status === 'accepted') ? new Date().toISOString() : sub.reviewed_at;

  db.prepare(`
    UPDATE submissions SET status=?, teacher_note=?, grade=?, reviewed_at=? WHERE id=?
  `).run(statusVal, noteVal, gradeVal, reviewedAt, sub.id);

  // Notify student
  try {
    const assignTitle = sub.assignment_id
      ? db.prepare('SELECT title FROM assignments WHERE id = ?').get(sub.assignment_id)?.title
      : null;
    const isGraded = gradeVal !== undefined && gradeVal !== null;

    if (status === 'revision') {
      const msg = assignTitle
        ? `Работа «${assignTitle}» отправлена на доработку.${noteVal ? ' Комментарий: ' + noteVal : ''}`
        : `Ваша работа отправлена на доработку.`;
      pushNotif(sub.student_id, 'revision', msg, '/homework');
    } else if (status === 'accepted' || (status === 'reviewed' && sub.status !== 'reviewed')) {
      const gradeText = isGraded ? ` Оценка: ${gradeVal}/100` : '';
      const statusText = status === 'accepted' ? 'принята' : 'проверена';
      const msg = assignTitle
        ? `Ваша работа «${assignTitle}» ${statusText}.${gradeText}`
        : `Ваша работа ${statusText}.${gradeText}`;
      pushNotif(sub.student_id, 'grade', msg, '/homework');
    } else if (isGraded && !status) {
      const msg = assignTitle
        ? `Оценка за «${assignTitle}»: ${gradeVal}/100`
        : `Оценка за работу: ${gradeVal}/100`;
      pushNotif(sub.student_id, 'grade', msg, '/homework');
    }
    // Notify parents
    if (isGraded || status === 'accepted' || status === 'reviewed') {
      const gradeText = isGraded ? ` Оценка: ${gradeVal}/100` : '';
      const parentMsg = assignTitle
        ? `Работа «${assignTitle}» проверена.${gradeText}`
        : `Работа проверена.${gradeText}`;
      pushParentNotif(sub.student_id, 'grade', parentMsg);
    }
  } catch (e) { console.error('[submissions] notify student grade:', e.message); }

  res.json({ ok: true });
}

/* ── GET /api/submissions/:id/download ────────────────────────────────── */
function downloadSubmission(req, res) {
  const sub = db.prepare(`
    SELECT s.*, c.teacher_id FROM submissions s
    JOIN classes c ON c.id = s.class_id WHERE s.id = ?
  `).get(Number(req.params.id));
  if (!sub) return res.status(404).json({ error: 'Submission not found' });

  const uid       = req.user.id;
  const isTeacher = ['teacher', 'admin'].includes(req.user.role);

  if (!isTeacher && sub.student_id !== uid) return res.status(403).json({ error: 'Forbidden' });
  if (req.user.role === 'teacher' && sub.teacher_id !== uid) return res.status(403).json({ error: 'Forbidden' });

  const filePath = path.resolve(UPLOADS_DIR, sub.stored_name);
  if (!filePath.startsWith(UPLOADS_DIR + path.sep))
    return res.status(400).json({ error: 'Invalid path' });
  if (!fs.existsSync(filePath)) return res.status(404).json({ error: 'File missing' });

  const encoded = encodeURIComponent(sub.original_name);
  res.setHeader('Content-Disposition', `attachment; filename="${encoded}"; filename*=UTF-8''${encoded}`);
  res.setHeader('Content-Type', sub.mimetype || 'application/octet-stream');
  res.sendFile(filePath);
}

/* ── DELETE /api/submissions/:id ───────────────────────────────────────── */
function deleteSubmission(req, res) {
  const sub = db.prepare('SELECT s.*, c.teacher_id FROM submissions s JOIN classes c ON c.id = s.class_id WHERE s.id = ?')
    .get(Number(req.params.id));
  if (!sub) return res.status(404).json({ error: 'Submission not found' });

  const isOwner   = sub.student_id === req.user.id;
  const isAdmin   = req.user.role === 'admin';
  const isTeacher = req.user.role === 'teacher' && sub.teacher_id === req.user.id;

  if (!isOwner && !isAdmin && !isTeacher) return res.status(403).json({ error: 'Forbidden' });
  // Students can't delete reviewed/accepted submissions; teachers/admin can
  if (isOwner && !isAdmin && !isTeacher && ['reviewed', 'accepted'].includes(sub.status))
    return res.status(400).json({ error: 'Cannot delete a reviewed submission' });

  // Audit log — record who deleted what
  const studentName = db.prepare('SELECT name FROM users WHERE id = ?').get(sub.student_id)?.name || '';
  db.prepare(`
    INSERT INTO submission_log (submission_id, class_id, assignment_id, student_id, student_name,
      original_name, status, grade, teacher_note, submitted_at, action, deleted_by, deleted_by_role)
    VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, 'deleted', ?, ?)
  `).run(sub.id, sub.class_id, sub.assignment_id, sub.student_id, studentName,
    sub.original_name, sub.status, sub.grade, sub.teacher_note, sub.submitted_at,
    req.user.id, req.user.role);

  const filePath = path.resolve(UPLOADS_DIR, sub.stored_name);
  if (filePath.startsWith(UPLOADS_DIR + path.sep)) { try { fs.unlinkSync(filePath); } catch {} }
  db.prepare('DELETE FROM submissions WHERE id = ?').run(sub.id);
  res.json({ ok: true });
}

/* ── POST /api/submissions/:id/resubmit  (student — only if revision) ──── */
function resubmit(req, res) {
  if (!req.file) return res.status(400).json({ error: 'No file uploaded' });
  const sub = db.prepare('SELECT * FROM submissions WHERE id = ?').get(Number(req.params.id));
  if (!sub) return res.status(404).json({ error: 'Submission not found' });
  if (sub.student_id !== req.user.id) return res.status(403).json({ error: 'Forbidden' });
  if (sub.status !== 'revision') return res.status(400).json({ error: 'Resubmit only allowed for revision status' });

  // Magic bytes verification on resubmit
  const resubPath = path.resolve(UPLOADS_DIR, req.file.filename);
  if (!checkMagicBytes(resubPath, req.file.mimetype)) {
    try { fs.unlinkSync(resubPath); } catch {}
    return res.status(400).json({ error: 'Содержимое файла не соответствует его расширению' });
  }

  // Delete old file
  const oldPath = path.resolve(UPLOADS_DIR, sub.stored_name);
  if (oldPath.startsWith(UPLOADS_DIR + path.sep)) { try { fs.unlinkSync(oldPath); } catch {} }

  const message = req.body.message?.trim() || null;

  try {
    db.prepare(`
      UPDATE submissions SET original_name=?, stored_name=?, mimetype=?, size=?, message=?,
        status='resubmitted', submitted_at=datetime('now'), teacher_note=NULL
      WHERE id=?
    `).run(req.file.originalname, req.file.filename, req.file.mimetype, req.file.size, message, sub.id);
  } catch (err) {
    const fp = path.resolve(UPLOADS_DIR, req.file.filename);
    if (fp.startsWith(UPLOADS_DIR + path.sep)) { try { fs.unlinkSync(fp); } catch {} }
    throw err;
  }

  // Notify teacher
  try {
    const cls = db.prepare('SELECT teacher_id, name FROM classes WHERE id = ?').get(sub.class_id);
    if (cls?.teacher_id) {
      const assignTitle = sub.assignment_id
        ? db.prepare('SELECT title FROM assignments WHERE id = ?').get(sub.assignment_id)?.title
        : null;
      const studentName = req.user.name || req.user.email;
      const msg = assignTitle
        ? `«${studentName}» повторно сдал работу «${assignTitle}»`
        : `«${studentName}» повторно сдал работу`;
      pushNotif(cls.teacher_id, 'submission', msg, '/homework');
    }
  } catch (e) { console.error('[submissions] notify teacher resubmit:', e.message); }

  res.json({ ok: true });
}

/* ── GET /api/submissions/log?class_id=X  (admin only) ─────────────────── */
function getSubmissionLog(req, res) {
  const { class_id } = req.query;
  let sql = `
    SELECT sl.*, u.name AS deleted_by_name,
           c.name AS class_name, a.title AS assignment_title
    FROM submission_log sl
    LEFT JOIN users u ON u.id = sl.deleted_by
    LEFT JOIN classes c ON c.id = sl.class_id
    LEFT JOIN assignments a ON a.id = sl.assignment_id
  `;
  const args = [];
  if (class_id) {
    sql += ' WHERE sl.class_id = ?';
    args.push(Number(class_id));
  }
  sql += ' ORDER BY sl.deleted_at DESC LIMIT 200';
  res.json(db.prepare(sql).all(...args));
}

/* ── DELETE /api/submissions/log  (admin only) ─────────────────────────── */
function clearSubmissionLog(req, res) {
  db.prepare('DELETE FROM submission_log').run();
  res.json({ ok: true });
}

module.exports = { submit, getMySubmissions, getClassSubmissions, reviewSubmission, downloadSubmission, deleteSubmission, resubmit, getSubmissionLog, clearSubmissionLog };
