const { pointAtDevDb } = require('./setup');
pointAtDevDb();
process.env.ENABLE_LICENSING_IN_TESTS = 'true';

const crypto = require('crypto');
const express = require('express');
const request = require('supertest');
const licensingRouter = require('../src/controllers/licensing.controller');
const LicenseCache = require('../src/services/LicenseCacheService');

const { privateKey: TEST_PRIV_KEY, publicKey: TEST_PUB_KEY } = crypto.generateKeyPairSync('ed25519', {
  privateKeyEncoding: { type: 'pkcs8', format: 'pem' },
  publicKeyEncoding: { type: 'spki', format: 'pem' }
});

const { privateKey: OTHER_PRIV_KEY } = crypto.generateKeyPairSync('ed25519', {
  privateKeyEncoding: { type: 'pkcs8', format: 'pem' },
  publicKeyEncoding: { type: 'spki', format: 'pem' }
});

const TENANT_ID = '5b39bcb5-506a-456d-b7cb-91730b397cc1';

function createSignedJwt(claims, privKey = TEST_PRIV_KEY) {
  const headerB64 = Buffer.from(JSON.stringify({ alg: 'EdDSA', typ: 'JWT' })).toString('base64url');
  const payloadB64 = Buffer.from(JSON.stringify(claims)).toString('base64url');
  const data = Buffer.from(`${headerB64}.${payloadB64}`, 'utf8');
  const sigB64 = crypto.sign(null, data, privKey).toString('base64url');
  return `${headerB64}.${payloadB64}.${sigB64}`;
}

describe('Offline License Artifact Ingestion Endpoint (POST /api/license/ingest)', () => {
  let app;
  let originalPubKey;

  beforeEach(async () => {
    originalPubKey = process.env.SUPERADMIN_PUBLIC_KEY;
    process.env.SUPERADMIN_PUBLIC_KEY = TEST_PUB_KEY;
    await LicenseCache.del(TENANT_ID);

    app = express();
    app.use(express.json());
    app.use('/api/license', licensingRouter);
  });

  afterEach(async () => {
    process.env.SUPERADMIN_PUBLIC_KEY = originalPubKey;
    await LicenseCache.del(TENANT_ID);
  });

  it('successfully verifies and ingests a valid signed .lic.json artifact', async () => {
    const claims = {
      iss: 'super_admin_licensing_engine',
      sub: TENANT_ID,
      tenant_code: 'SCH-TEST',
      term: 'Term 3 Offline',
      academic_year: '2026',
      max_students: 2500,
      max_staff: 350,
      nbf: Math.floor(Date.now() / 1000) - 100,
      exp: Math.floor(Date.now() / 1000) + 86400 * 90,
      status: 'active'
    };
    const signedToken = createSignedJwt(claims);

    const artifact = {
      format_version: '1.0',
      issued_at: new Date().toISOString(),
      issued_by: 'Nextgen LMS SuperAdmin Governance Portal',
      tenant: {
        id: TENANT_ID,
        code: 'SCH-TEST',
        name: 'Test Academy'
      },
      license: {
        id: 'lic-offline-test-101',
        license_key: 'LIC-TERM3OFFLINE-2026-TEST',
        signed_license_token: signedToken,
        algorithm: 'EdDSA',
        term_name: 'Term 3 Offline',
        academic_year: '2026',
        start_date: '2026-07-01',
        end_date: '2026-10-01',
        grace_period_days: 7,
        max_students: 2500,
        max_staff: 350,
        status: 'active'
      },
      checksum: crypto.createHash('sha256').update(signedToken).digest('hex')
    };

    const res = await request(app)
      .post('/api/license/ingest')
      .set('x-tenant-id', TENANT_ID)
      .send(artifact);

    expect(res.status).toBe(200);
    expect(res.body.ok).toBe(true);
    expect(res.body.status).toBe('ACTIVE');
    expect(res.body.license.license_key).toBe('LIC-TERM3OFFLINE-2026-TEST');
    expect(res.body.license.term_name).toBe('Term 3 Offline');
  });

  it('rejects an artifact signed with an untrusted / invalid key', async () => {
    const claims = {
      iss: 'fake_super_admin',
      sub: TENANT_ID,
      term: 'Term Forged',
      exp: Math.floor(Date.now() / 1000) + 86400 * 90
    };
    const forgedToken = createSignedJwt(claims, OTHER_PRIV_KEY);

    const forgedArtifact = {
      format_version: '1.0',
      license: {
        signed_license_token: forgedToken,
        term_name: 'Term Forged'
      }
    };

    const res = await request(app)
      .post('/api/license/ingest')
      .set('x-tenant-id', TENANT_ID)
      .send(forgedArtifact);

    expect(res.status).toBe(422);
    expect(res.body.error).toMatch(/Cryptographic signature verification failed/);
  });

  it('successfully decrypts and ingests an AES-256-GCM encrypted license artifact package', async () => {
    const claims = {
      iss: 'super_admin_licensing_engine',
      sub: TENANT_ID,
      tenant_code: 'SCH-ENC',
      term: 'Term 1 Encrypted',
      academic_year: '2026',
      max_students: 5000,
      max_staff: 400,
      exp: Math.floor(Date.now() / 1000) + 86400 * 90,
      status: 'active'
    };
    const token = createSignedJwt(claims);

    const rawArtifact = {
      tenant: { id: TENANT_ID, code: 'SCH-ENC', name: 'Encrypted Academy' },
      license: {
        id: 'lic-enc-001',
        license_key: 'LIC-ENC-2026',
        signed_license_token: token,
        term_name: 'Term 1 Encrypted',
        academic_year: '2026',
        start_date: '2026-07-01',
        end_date: '2026-10-01',
        max_students: 5000,
        max_staff: 400,
        status: 'active'
      }
    };

    const secret = process.env.LICENSE_ARTIFACT_SECRET || TEST_PUB_KEY;
    const key = crypto.createHash('sha256').update(`${secret}:${TENANT_ID}`).digest();
    const iv = crypto.randomBytes(12);
    const cipher = crypto.createCipheriv('aes-256-gcm', key, iv);
    const encrypted = Buffer.concat([cipher.update(JSON.stringify(rawArtifact), 'utf8'), cipher.final()]);
    const authTag = cipher.getAuthTag();

    const encryptedEnvelope = {
      format_version: '2.0',
      encrypted: true,
      algorithm: 'AES-256-GCM + Ed25519',
      tenant_id: TENANT_ID,
      iv: iv.toString('hex'),
      auth_tag: authTag.toString('hex'),
      ciphertext: encrypted.toString('base64')
    };

    const res = await request(app)
      .post('/api/license/ingest')
      .set('x-tenant-id', TENANT_ID)
      .send(encryptedEnvelope);

    expect(res.status).toBe(200);
    expect(res.body.ok).toBe(true);
    expect(res.body.license.term_name).toBe('Term 1 Encrypted');
  });

  it('rejects tampered ciphertext in an encrypted license artifact package', async () => {
    const encryptedEnvelope = {
      format_version: '2.0',
      encrypted: true,
      algorithm: 'AES-256-GCM + Ed25519',
      tenant_id: TENANT_ID,
      iv: crypto.randomBytes(12).toString('hex'),
      auth_tag: crypto.randomBytes(16).toString('hex'),
      ciphertext: Buffer.from('TAMPERED_CIPHERTEXT_BYTES').toString('base64')
    };

    const res = await request(app)
      .post('/api/license/ingest')
      .set('x-tenant-id', TENANT_ID)
      .send(encryptedEnvelope);

    expect(res.status).toBe(422);
    expect(res.body.error).toMatch(/Artifact decryption \/ tamper check failed/);
  });
});
