'use strict';
const { test, after } = require('node:test');
const assert = require('node:assert/strict');
const { db, inject, getToken, cleanup } = require('./setup');

after(() => cleanup());

/* 1. Student cannot delete a teacher's class ─────────────────────────────── */
test('student cannot delete another teacher\'s class', async () => {
  const teacher = await getToken('teacher');
  const student = await getToken('student');

  const create = await inject('POST', '/api/classes', { name: 'Security test class 1' }, teacher.token);
  assert.ok(create.status < 300, `create failed: ${JSON.stringify(create.body)}`);
  const classId = create.body.id;

  const del = await inject('DELETE', `/api/classes/${classId}`, null, student.token);
  assert.equal(del.status, 403, `expected 403, got ${del.status}: ${JSON.stringify(del.body)}`);

  // Class must still exist
  const row = db.prepare('SELECT id FROM classes WHERE id = ?').get(classId);
  assert.ok(row, 'class was deleted — IDOR confirmed');
});

/* 2. Teacher A cannot delete Teacher B's class ───────────────────────────── */
test('teacher cannot delete another teacher\'s class', async () => {
  const tA = await getToken('teacher');
  const tB = await getToken('teacher');

  const create = await inject('POST', '/api/classes', { name: 'Teacher B class' }, tB.token);
  assert.ok(create.status < 300, `create failed: ${JSON.stringify(create.body)}`);
  const classId = create.body.id;

  const del = await inject('DELETE', `/api/classes/${classId}`, null, tA.token);
  assert.equal(del.status, 403, `expected 403, got ${del.status}: ${JSON.stringify(del.body)}`);

  const row = db.prepare('SELECT id FROM classes WHERE id = ?').get(classId);
  assert.ok(row, 'class was deleted by wrong teacher — IDOR confirmed');
});

/* 3. Banned user is blocked on protected routes ─────────────────────────── */
test('banned user is blocked on protected routes', async () => {
  const u = await getToken('student');

  // Token works before ban
  const before = await inject('GET', '/api/auth/me', null, u.token);
  assert.equal(before.status, 200);

  db.prepare('UPDATE users SET is_banned = 1 WHERE id = ?').run(u.userId);

  const after = await inject('GET', '/api/auth/me', null, u.token);
  assert.equal(after.status, 403, `expected 403 for banned user, got ${after.status}`);
  assert.ok(
    /заблокирован|banned/i.test(after.body.error || ''),
    `expected ban message, got: ${after.body.error}`
  );

  // Cleanup
  db.prepare('UPDATE users SET is_banned = 0 WHERE id = ?').run(u.userId);
});

/* 4. Token is revoked when token_version is bumped ──────────────────────── */
test('token revoked when token_version changes', async () => {
  const u = await getToken('student');

  // Token works
  const ok = await inject('GET', '/api/auth/me', null, u.token);
  assert.equal(ok.status, 200);

  // Simulate password change (bumps token_version)
  db.prepare('UPDATE users SET token_version = COALESCE(token_version, 0) + 1 WHERE id = ?').run(u.userId);

  const revoked = await inject('GET', '/api/auth/me', null, u.token);
  assert.equal(revoked.status, 401, `expected 401 after token_version bump, got ${revoked.status}`);
});

/* 5. Student cannot join class with wrong invite code ───────────────────── */
test('join with wrong invite code returns 404', async () => {
  const student = await getToken('student');

  const join = await inject('POST', '/api/classes/join', { invite_code: 'WRONG-XXXX-0000' }, student.token);
  assert.ok(join.status === 404 || join.status === 400,
    `expected 404 or 400, got ${join.status}: ${JSON.stringify(join.body)}`);

  // Verify no class membership was created
  const membership = db.prepare('SELECT 1 FROM class_members WHERE user_id = ?').get(student.userId);
  assert.equal(membership, undefined, 'student joined a class with wrong code');
});

/* 6. Admin-only route blocks teacher ────────────────────────────────────── */
test('admin-only GET /admin/users blocks teacher', async () => {
  const teacher = await getToken('teacher');

  const res = await inject('GET', '/api/admin/users', null, teacher.token);
  assert.equal(res.status, 403, `expected 403 for teacher on admin route, got ${res.status}`);
});

/* 7. Protected route without token returns 401 ──────────────────────────── */
test('protected route without token returns 401', async () => {
  const res = await inject('GET', '/api/auth/me', null, null);
  assert.equal(res.status, 401);
});
