const db = require('../db/db');
const { audit } = require('../utils/audit');
const registry = require('../permissions/registry');

/* ── All known permissions — sourced from central registry ────────────── */
// Only teacher and student entries are exposed to the admin UI.
// free_student shares the same keys as student (handled in auth.js fallback).
const ALL_PERMISSIONS = [
  ...registry.byRole('teacher'),
  ...registry.byRole('student'),
];

/* ── Seed defaults once per startup ───────────────────────────────────── */
function seedDefaults() {
  const upsert = db.prepare(
    'INSERT OR IGNORE INTO role_permissions (role, permission, enabled) VALUES (?, ?, ?)'
  );
  const run = db.transaction(() => {
    for (const p of ALL_PERMISSIONS) upsert.run(p.role, p.key, p.default);
  });
  run();
}

/* ── GET /api/permissions ─────────────────────────────────────────────── */
function getPermissions(_req, res) {
  seedDefaults();
  const rows = db.prepare('SELECT role, permission, enabled FROM role_permissions').all();
  const map = { teacher: {}, student: {} };
  for (const r of rows) {
    if (map[r.role]) map[r.role][r.permission] = r.enabled === 1;
  }
  res.json({ permissions: map, definitions: ALL_PERMISSIONS });
}

/* ── POST /api/permissions  { role, permission, enabled } ─────────────── */
function setPermission(req, res) {
  const { role, permission, enabled } = req.body;
  if (!['teacher', 'student'].includes(role))
    return res.status(400).json({ error: 'Invalid role' });
  if (!ALL_PERMISSIONS.find(p => p.key === permission && p.role === role))
    return res.status(400).json({ error: 'Unknown permission' });
  db.transaction(() => {
    db.prepare(
      'INSERT OR REPLACE INTO role_permissions (role, permission, enabled) VALUES (?, ?, ?)'
    ).run(role, permission, enabled ? 1 : 0);
    // Invalidate JWTs for all users of that role so the change takes effect immediately
    db.prepare(
      'UPDATE users SET token_version = token_version + 1 WHERE role = ?'
    ).run(role);
  })();
  audit(req, 'permission.set', `role:${role}/${permission}`, `enabled=${enabled ? 1 : 0}`);
  res.json({ ok: true });
}

/* ── GET /api/permissions/me  (any authenticated user) ───────────────── */
function getMyPermissions(req, res) {
  const uid  = req.user.id;
  const role = req.user.role;
  if (role === 'admin') return res.json({ role, permissions: [] }); // admins bypass all

  seedDefaults();
  const roleRows = db.prepare(
    'SELECT permission, enabled FROM role_permissions WHERE role = ?'
  ).all(role);
  const roleMap = {};
  for (const r of roleRows) roleMap[r.permission] = r.enabled === 1;

  const userRows = db.prepare(
    'SELECT permission, enabled FROM user_permissions WHERE user_id = ?'
  ).all(uid);
  const userMap = {};
  for (const r of userRows) userMap[r.permission] = r.enabled === 1;

  const defs = ALL_PERMISSIONS.filter(p => p.role === role);
  const result = defs.map(d => ({
    key:       d.key,
    effective: userMap[d.key] !== undefined ? userMap[d.key] : (roleMap[d.key] ?? !!d.default),
  }));
  res.json({ role, permissions: result });
}

/* ── GET /api/permissions/users/:id ──────────────────────────────────── */
function getUserPermissions(req, res) {
  const uid = Number(req.params.id);
  const target = db.prepare('SELECT id, role FROM users WHERE id = ?').get(uid);
  if (!target) return res.status(404).json({ error: 'User not found' });

  seedDefaults();
  // role-level values
  const roleRows = db.prepare(
    'SELECT permission, enabled FROM role_permissions WHERE role = ?'
  ).all(target.role);
  const roleMap = {};
  for (const r of roleRows) roleMap[r.permission] = r.enabled === 1;

  // user-level overrides
  const userRows = db.prepare(
    'SELECT permission, enabled FROM user_permissions WHERE user_id = ?'
  ).all(uid);
  const userMap = {};
  for (const r of userRows) userMap[r.permission] = r.enabled === 1;

  const defs = ALL_PERMISSIONS.filter(p => p.role === target.role);
  const result = defs.map(d => ({
    key:      d.key,
    label:    d.label,
    desc:     d.desc,
    roleVal:  roleMap[d.key] ?? d.default,  // effective role-level value
    userVal:  userMap[d.key],                // undefined = no override
    effective: userMap[d.key] !== undefined ? userMap[d.key] : (roleMap[d.key] ?? !!d.default),
  }));

  res.json({ role: target.role, permissions: result });
}

/* ── POST /api/permissions/users/:id  { permission, enabled } ─────────── */
function setUserPermission(req, res) {
  const uid = Number(req.params.id);
  const { permission, enabled } = req.body;
  const target = db.prepare('SELECT role FROM users WHERE id = ?').get(uid);
  if (!target) return res.status(404).json({ error: 'User not found' });
  if (!ALL_PERMISSIONS.find(p => p.key === permission && p.role === target.role))
    return res.status(400).json({ error: 'Unknown permission for this role' });
  db.transaction(() => {
    db.prepare(
      'INSERT OR REPLACE INTO user_permissions (user_id, permission, enabled) VALUES (?, ?, ?)'
    ).run(uid, permission, enabled ? 1 : 0);
    // Invalidate existing JWT for this user immediately
    db.prepare(
      'UPDATE users SET token_version = token_version + 1 WHERE id = ?'
    ).run(uid);
  })();
  audit(req, 'permission.user_set', `user:${uid}/${permission}`, `enabled=${enabled ? 1 : 0}`);
  res.json({ ok: true });
}

/* ── DELETE /api/permissions/users/:id/reset  (single or all) ─────────── */
function resetUserPermissions(req, res) {
  const uid = Number(req.params.id);
  const { permission } = req.body; // optional: reset one key
  db.transaction(() => {
    if (permission) {
      db.prepare(
        'DELETE FROM user_permissions WHERE user_id = ? AND permission = ?'
      ).run(uid, permission);
    } else {
      db.prepare('DELETE FROM user_permissions WHERE user_id = ?').run(uid);
    }
    // Bump token_version so the user's JWT picks up the new effective permissions
    // immediately (could be a downgrade if override was =1 and role default is =0).
    db.prepare('UPDATE users SET token_version = token_version + 1 WHERE id = ?').run(uid);
  })();
  audit(req, 'permission.user_reset', `user:${uid}`, permission || null);
  res.json({ ok: true });
}

module.exports = { getPermissions, setPermission, seedDefaults, ALL_PERMISSIONS, getMyPermissions, getUserPermissions, setUserPermission, resetUserPermissions };
