// Tests for the Phase 1 wiring routes added to fees.controller.js and
// transfers.controller.js. Validates FR-SMS4 (sub-paths) and FR-XFER2
// (graduation export).

const { pointAtDevDb } = require('./setup');

pointAtDevDb();
const request = require('supertest');
const app = require('../src/index');

describe('SRS Phase 1 wiring — FR-SMS4 sub-paths + FR-XFER2 graduation', () => {
  let adminToken;
  let studentToken;
  let parentToken;

  beforeAll(async () => {
    const r1 = await request(app).post('/api/auth/login').send({ email: 'admin@school.com', password: 'admin123' });
    adminToken = r1.body?.token;
    const r2 = await request(app).post('/api/auth/login').send({ email: 'student@school.com', password: 'student123' });
    studentToken = r2.body?.token;
    const r3 = await request(app).post('/api/auth/login').send({ email: 'parent@school.com', password: 'parent123' });
    parentToken = r3.body?.token;
  });

  // ==================== FR-SMS4: /api/fees/structure ====================

  describe('GET /api/fees/structure', () => {
    it('returns 200 with the full fee structure for an admin', async () => {
      const res = await request(app)
        .get('/api/fees/structure')
        .set('Authorization', `Bearer ${adminToken}`);
      expect(res.status).toBe(200);
      expect(res.body).toHaveProperty('academic_year');
      expect(res.body).toHaveProperty('fee_groups');
      expect(res.body).toHaveProperty('fee_plans');
      expect(res.body).toHaveProperty('active_discounts');
      expect(res.body).toHaveProperty('outstanding_by_class');
      expect(Array.isArray(res.body.fee_groups)).toBe(true);
      expect(Array.isArray(res.body.fee_plans)).toBe(true);
      expect(Array.isArray(res.body.active_discounts)).toBe(true);
      expect(Array.isArray(res.body.outstanding_by_class)).toBe(true);
    });

    it('returns 200 for a student (read-only meta is public-ish)', async () => {
      const res = await request(app)
        .get('/api/fees/structure')
        .set('Authorization', `Bearer ${studentToken}`);
      expect(res.status).toBe(200);
    });

    it('returns 401 without a token', async () => {
      const res = await request(app).get('/api/fees/structure');
      expect(res.status).toBe(401);
    });

    it('honours the academic_year query param', async () => {
      const res = await request(app)
        .get('/api/fees/structure?academic_year=2025')
        .set('Authorization', `Bearer ${adminToken}`);
      expect(res.status).toBe(200);
      expect(res.body.academic_year).toBe('2025');
    });
  });

  // ==================== FR-SMS4: /api/fees/invoices ====================

  describe('GET /api/fees/invoices', () => {
    it('returns 200 with an array (admin)', async () => {
      const res = await request(app)
        .get('/api/fees/invoices')
        .set('Authorization', `Bearer ${adminToken}`);
      expect(res.status).toBe(200);
      expect(Array.isArray(res.body)).toBe(true);
    });

    it('returns 403 for a student (finance roles only)', async () => {
      const res = await request(app)
        .get('/api/fees/invoices')
        .set('Authorization', `Bearer ${studentToken}`);
      expect(res.status).toBe(403);
    });

    it('returns 401 without a token', async () => {
      const res = await request(app).get('/api/fees/invoices');
      expect(res.status).toBe(401);
    });
  });

  // ==================== FR-XFER2: /api/xfer/graduation ====================

  describe('POST /api/xfer/graduation', () => {
    it('returns 200 with a complete graduation package for admin', async () => {
      const res = await request(app)
        .post('/api/xfer/graduation')
        .set('Authorization', `Bearer ${adminToken}`)
        .send({ student_id: 4, target_institution: 'University of Zimbabwe' });
      expect(res.status).toBe(200);
      expect(res.body.package_type).toBe('graduation_export');
      expect(res.body.schema_version).toBe('1.0');
      expect(res.body.student.first_name).toBeTruthy();
      expect(res.body).toHaveProperty('academic_history');
      expect(res.body).toHaveProperty('attendance_summary');
      expect(res.body).toHaveProperty('disciplinary_record');
      expect(res.body).toHaveProperty('financial_clearance');
      expect(res.body).toHaveProperty('signature');
      expect(res.body.signature.signature_digest).toMatch(/^[a-f0-9]{64}$/);
    });

    it('returns 400 when target_institution is missing', async () => {
      const res = await request(app)
        .post('/api/xfer/graduation')
        .set('Authorization', `Bearer ${adminToken}`)
        .send({ student_id: 4 });
      expect(res.status).toBe(400);
      expect(res.body.error).toMatch(/target_institution/);
    });

    it('returns 400 when both student_id and student_uid are missing', async () => {
      const res = await request(app)
        .post('/api/xfer/graduation')
        .set('Authorization', `Bearer ${adminToken}`)
        .send({ target_institution: 'X' });
      expect(res.status).toBe(400);
    });

    it('returns 404 when the student does not exist', async () => {
      const res = await request(app)
        .post('/api/xfer/graduation')
        .set('Authorization', `Bearer ${adminToken}`)
        .send({ student_id: 99999, target_institution: 'X' });
      expect(res.status).toBe(404);
    });

    it('returns 403 when a student tries to read another student', async () => {
      // student@school.com resolves to id 4 in the dev seed; pick a
      // different student (id 9 = a generated 'Test User' student from
      // the e2e seed) to exercise the cross-student RBAC check.
      const res = await request(app)
        .post('/api/xfer/graduation')
        .set('Authorization', `Bearer ${studentToken}`)
        .send({ student_id: 9, target_institution: 'X' });
      expect(res.status).toBe(403);
    });

    it('accepts a consent_id and gates on consent_status', async () => {
      // First, create a consent row
      const Database = require('better-sqlite3');
      const db = new Database(process.env.DB_PATH);
      db.pragma('foreign_keys = ON');
      // Ensure table exists (the controller creates it on first hit)
      const exists = db.prepare("SELECT name FROM sqlite_master WHERE type='table' AND name='transfer_consents'").get();
      if (!exists) {
        // Hit the controller first to create the table
        await request(app)
          .post('/api/xfer/graduation')
          .set('Authorization', `Bearer ${adminToken}`)
          .send({ student_id: 4, target_institution: 'X' });
        db.close();
        const db2 = new Database(process.env.DB_PATH);
        const { v4: uuidv4 } = require('uuid');
        const consentUid = uuidv4();
        db2.prepare(`
          INSERT INTO transfer_consents (uid, student_id, requested_by, target_school, consent_status, sync_status)
          VALUES (?, 4, 'audit@test', 'University of Zimbabwe', 'pending', 'pending')
        `).run(consentUid);
        db2.close();

        // Now try to export with that pending consent — must be 409
        const res = await request(app)
          .post('/api/xfer/graduation')
          .set('Authorization', `Bearer ${adminToken}`)
          .send({ student_id: 4, target_institution: 'University of Zimbabwe', consent_id: consentUid });
        expect(res.status).toBe(409);
        expect(res.body.consent_status).toBe('pending');
      } else {
        // Table already exists; insert a pending consent directly
        const { v4: uuidv4 } = require('uuid');
        const consentUid = uuidv4();
        db.prepare(`
          INSERT INTO transfer_consents (uid, student_id, requested_by, target_school, consent_status, sync_status)
          VALUES (?, 4, 'audit@test', 'University of Zimbabwe', 'pending', 'pending')
        `).run(consentUid);
        db.close();

        const res = await request(app)
          .post('/api/xfer/graduation')
          .set('Authorization', `Bearer ${adminToken}`)
          .send({ student_id: 4, target_institution: 'University of Zimbabwe', consent_id: consentUid });
        expect(res.status).toBe(409);
        expect(res.body.consent_status).toBe('pending');
      }
    });

    it('passes when consent is approved (signature includes consent metadata)', async () => {
      const Database = require('better-sqlite3');
      const db = new Database(process.env.DB_PATH);
      const { v4: uuidv4 } = require('uuid');
      const consentUid = uuidv4();
      db.prepare(`
        INSERT INTO transfer_consents (uid, student_id, requested_by, target_school, consent_status, signed_at, signature_hash, sync_status)
        VALUES (?, 4, 'audit@test', 'University of Zimbabwe', 'approved', datetime('now','localtime'), 'abc123', 'pending')
      `).run(consentUid);
      db.close();

      const res = await request(app)
        .post('/api/xfer/graduation')
        .set('Authorization', `Bearer ${adminToken}`)
        .send({ student_id: 4, target_institution: 'University of Zimbabwe', consent_id: consentUid });
      expect(res.status).toBe(200);
      expect(res.body.consent).toBeTruthy();
      expect(res.body.consent.consent_id).toBe(consentUid);
      expect(res.body.consent.consent_status).toBe('approved');
    });
  });
});
