'use strict';
/* /api/access — управление доступом к учебникам и экзамен-модулям.
 *
 * Доступно админам (все классы/ученики) и учителям (только свои классы и
 * ученики своих классов / привязанные ученики). Модель — allowlist,
 * правило ученика важнее правила класса (см. services/contentAccess.js). */
const router = require('express').Router();
const db = require('../db/db');
const { authMiddleware, requireRole } = require('../middleware/auth');
const { audit } = require('../utils/audit');

router.use(authMiddleware);
router.use(requireRole('admin', 'teacher'));

const isAdmin = (req) => req.user.role === 'admin';

/* ── Каталог контента, которым можно управлять ─────────────────────────── */
/* GET /api/access/catalog → { textbooks:[...], exams:[...] } */
router.get('/catalog', (_req, res) => {
  const textbooks = db.prepare(`
    SELECT slug, title, subject, grade, color
      FROM textbooks
     WHERE is_active = 1 AND parent_slug IS NULL
     ORDER BY sort_order, subject, grade
  `).all();
  const exams = db.prepare(`
    SELECT exam_key, title, subject_slug, grade
      FROM exam_tracks
     WHERE enabled = 1
     ORDER BY sort_order, exam_key
  `).all();
  res.json({ textbooks, exams });
});

/* ── Цели назначения: классы (+ученики) и отдельные ученики ────────────── */
/* GET /api/access/targets → { classes:[{id,name,students:[...]}], looseStudents:[...] } */
router.get('/targets', (req, res) => {
  const admin = isAdmin(req);

  const classes = admin
    ? db.prepare(`SELECT c.id, c.name, u.name AS teacher_name
                    FROM classes c LEFT JOIN users u ON u.id = c.teacher_id
                   ORDER BY c.name`).all()
    : db.prepare(`SELECT id, name FROM classes WHERE teacher_id = ? ORDER BY name`)
        .all(req.user.id);

  const membersStmt = db.prepare(`
    SELECT u.id, u.name, u.email
      FROM class_members cm JOIN users u ON u.id = cm.user_id
     WHERE cm.class_id = ?
     ORDER BY u.name
  `);
  const classList = classes.map(c => ({ ...c, students: membersStmt.all(c.id) }));

  /* «Отдельные ученики» — без класса (admin) / привязанные не в моих классах (teacher). */
  let looseStudents;
  if (admin) {
    looseStudents = db.prepare(`
      SELECT id, name, email FROM users
       WHERE role IN ('student','free_student')
         AND id NOT IN (SELECT user_id FROM class_members)
       ORDER BY name LIMIT 500
    `).all();
  } else {
    looseStudents = db.prepare(`
      SELECT u.id, u.name, u.email
        FROM teacher_students ts JOIN users u ON u.id = ts.student_id
       WHERE ts.teacher_id = ?
         AND u.id NOT IN (
           SELECT cm.user_id FROM class_members cm
             JOIN classes c ON c.id = cm.class_id
            WHERE c.teacher_id = ?)
       ORDER BY u.name
    `).all(req.user.id, req.user.id);
  }

  res.json({ classes: classList, looseStudents });
});

/* ── Сводка: сколько классов открыто по каждому контенту ───────────────── */
/* GET /api/access/summary
   → { totalClasses, textbooks:{[slug]:openCount}, exams:{[key]:openCount} } */
router.get('/summary', (req, res) => {
  const admin = isAdmin(req);
  const totalClasses = admin
    ? db.prepare('SELECT COUNT(*) n FROM classes').get().n
    : db.prepare('SELECT COUNT(*) n FROM classes WHERE teacher_id = ?').get(req.user.id).n;

  const rows = admin
    ? db.prepare(`
        SELECT content_type, content_ref, COUNT(DISTINCT target_id) n
          FROM content_access
         WHERE scope = 'class' AND allow = 1
         GROUP BY content_type, content_ref`).all()
    : db.prepare(`
        SELECT content_type, content_ref, COUNT(DISTINCT target_id) n
          FROM content_access
         WHERE scope = 'class' AND allow = 1
           AND target_id IN (SELECT id FROM classes WHERE teacher_id = ?)
         GROUP BY content_type, content_ref`).all(req.user.id);

  const textbooks = {}, exams = {};
  for (const r of rows) {
    if (r.content_type === 'textbook') textbooks[r.content_ref] = r.n;
    else exams[r.content_ref] = r.n;
  }
  res.json({ totalClasses, textbooks, exams });
});

/* ── Текущие правила для одного контента ───────────────────────────────── */
/* GET /api/access/rules?content_type=&content_ref=
   → { classRules:{[class_id]:allow}, studentRules:{[user_id]:allow} } */
router.get('/rules', (req, res) => {
  const { content_type, content_ref } = req.query;
  if (!['textbook', 'exam'].includes(content_type) || !content_ref) {
    return res.status(400).json({ error: 'content_type и content_ref обязательны' });
  }
  const rows = db.prepare(`
    SELECT scope, target_id, allow FROM content_access
     WHERE content_type = ? AND content_ref = ?
  `).all(content_type, content_ref);

  const classRules = {}, studentRules = {};
  for (const r of rows) {
    if (r.scope === 'class') classRules[r.target_id] = r.allow;
    else studentRules[r.target_id] = r.allow;
  }
  res.json({ classRules, studentRules });
});

/* ── Проверка прав учителя на конкретную цель ──────────────────────────── */
function teacherOwnsClass(teacherId, classId) {
  return !!db.prepare('SELECT 1 FROM classes WHERE id = ? AND teacher_id = ?').get(classId, teacherId);
}

/* ── Открытый классу контент (для вида «по классу») ────────────────────── */
/* GET /api/access/class/:id → { textbooks:[slug], exams:[exam_key] } (allow=1) */
router.get('/class/:id', requireRole('admin', 'teacher'), (req, res) => {
  const cid = Number(req.params.id);
  if (!Number.isInteger(cid) || cid <= 0) return res.status(400).json({ error: 'неверный id' });
  if (!isAdmin(req) && !teacherOwnsClass(req.user.id, cid)) {
    return res.status(403).json({ error: 'Нет прав на этот класс' });
  }
  const rows = db.prepare(`
    SELECT content_type, content_ref FROM content_access
     WHERE scope = 'class' AND target_id = ? AND allow = 1
  `).all(cid);
  const textbooks = [], exams = [];
  for (const r of rows) (r.content_type === 'textbook' ? textbooks : exams).push(r.content_ref);
  res.json({ textbooks, exams });
});
function teacherCanManageStudent(teacherId, studentId) {
  const inClass = db.prepare(`
    SELECT 1 FROM class_members cm JOIN classes c ON c.id = cm.class_id
     WHERE c.teacher_id = ? AND cm.user_id = ? LIMIT 1`).get(teacherId, studentId);
  if (inClass) return true;
  return !!db.prepare('SELECT 1 FROM teacher_students WHERE teacher_id = ? AND student_id = ?')
    .get(teacherId, studentId);
}

/* ── Установка / снятие правила ────────────────────────────────────────── */
/* POST /api/access/rules
   body: { content_type, content_ref, scope, target_id, allow }
   allow: 1 (открыть) | 0 (закрыть-исключение) | null/'inherit' (удалить правило) */
router.post('/rules', (req, res) => {
  const { content_type, content_ref, scope, target_id } = req.body || {};
  let { allow } = req.body || {};

  if (!['textbook', 'exam'].includes(content_type)) {
    return res.status(400).json({ error: 'неверный content_type' });
  }
  if (!['class', 'student'].includes(scope)) {
    return res.status(400).json({ error: 'неверный scope' });
  }
  const tid = Number(target_id);
  if (!Number.isInteger(tid) || tid <= 0) {
    return res.status(400).json({ error: 'неверный target_id' });
  }

  /* Валидация существования контента. */
  if (content_type === 'textbook') {
    const ok = db.prepare('SELECT 1 FROM textbooks WHERE slug = ? AND parent_slug IS NULL').get(content_ref);
    if (!ok) return res.status(404).json({ error: 'учебник не найден' });
  } else {
    const ok = db.prepare('SELECT 1 FROM exam_tracks WHERE exam_key = ?').get(content_ref);
    if (!ok) return res.status(404).json({ error: 'экзамен-трек не найден' });
  }

  /* Скоупинг учителя. */
  if (!isAdmin(req)) {
    const allowed = scope === 'class'
      ? teacherOwnsClass(req.user.id, tid)
      : teacherCanManageStudent(req.user.id, tid);
    if (!allowed) return res.status(403).json({ error: 'Нет прав на эту цель' });
  }

  /* allow === null / 'inherit' / undefined → удалить правило (наследование). */
  if (allow === null || allow === undefined || allow === 'inherit') {
    db.prepare(`DELETE FROM content_access
                 WHERE content_type = ? AND content_ref = ? AND scope = ? AND target_id = ?`)
      .run(content_type, content_ref, scope, tid);
    audit(req, 'access.inherit', `${content_type}:${content_ref}`, `${scope}:${tid}`);
    return res.json({ ok: true, allow: null });
  }

  allow = (allow === 1 || allow === true || allow === '1') ? 1 : 0;
  db.prepare(`
    INSERT INTO content_access (content_type, content_ref, scope, target_id, allow, created_by)
    VALUES (?, ?, ?, ?, ?, ?)
    ON CONFLICT (content_type, content_ref, scope, target_id)
    DO UPDATE SET allow = excluded.allow, created_by = excluded.created_by, created_at = datetime('now')
  `).run(content_type, content_ref, scope, tid, allow, req.user.id);

  audit(req, allow ? 'access.grant' : 'access.deny', `${content_type}:${content_ref}`, `${scope}:${tid}`);
  res.json({ ok: true, allow });
});

module.exports = router;
