const express = require('express');
const router = express.Router();
const path = require('path');
const crypto = require('crypto');
const Database = require('better-sqlite3');
const SupabaseLicenseService = require('../services/SupabaseLicenseService');
const LicenseCache = require('../services/LicenseCacheService');

const dbPath = process.env.DB_PATH || path.join(__dirname, '../../data/school.db');
const DEFAULT_TENANT_ID = '5b39bcb5-506a-456d-b7cb-91730b397cc1';

let db;
const getDb = () => {
  if (!db) {
    db = new Database(dbPath);
    db.pragma('foreign_keys = ON');
  }
  return db;
};

function resolveTenantId(req) {
  return (
    req.user?.tenant_id ||
    req.headers['x-tenant-id'] ||
    req.headers['x-tenant-code'] ||
    process.env.TENANT_ID ||
    DEFAULT_TENANT_ID
  );
}

function verifyEdDsaJwt(token, publicKeyPem) {
  const segments = token.split('.');
  if (segments.length !== 3) throw new Error('Invalid JWT format');
  const [headerB64, payloadB64, signatureB64] = segments;
  const header = JSON.parse(Buffer.from(headerB64, 'base64url').toString('utf8'));
  if (header.alg !== 'EdDSA') throw new Error('Invalid JWT algorithm');
  const data = Buffer.from(`${headerB64}.${payloadB64}`, 'utf8');
  const signature = Buffer.from(signatureB64, 'base64url');
  if (!crypto.verify(null, data, publicKeyPem.replace(/\\n/g, '\n'), signature)) {
    throw new Error('Invalid JWT signature');
  }
  return JSON.parse(Buffer.from(payloadB64, 'base64url').toString('utf8'));
}

function readTenantId(req) {
  return resolveTenantId(req);
}

function evaluateStatus(row) {
  if (!row || !row.signed_license_token) {
    return 'MISSING';
  }
  const token = row.signed_license_token;
  let status = 'INVALID';
  try {
    const publicKey = process.env.SUPERADMIN_PUBLIC_KEY;
    if (publicKey) {
      verifyEdDsaJwt(token, publicKey);
      const endDate = new Date(row.end_date);
      if (isNaN(endDate.getTime())) {
        status = 'INVALID';
      } else if (endDate < new Date()) {
        status = 'EXPIRED';
      } else {
        status = 'ACTIVE';
      }
    }
  } catch (_) {
    status = 'INVALID';
  }
  return status;
}

function rowToResponse(tenantId, row, source) {
  if (!row || !row.signed_license_token) {
    return {
      tenant_id: tenantId,
      status: 'MISSING',
      source,
      signed_license_token: null,
      algorithm: null,
      license_key: null,
      start_date: null,
      end_date: null,
      term_name: null,
      academic_year: null,
      max_students: null,
      max_staff: null,
    };
  }
  return {
    tenant_id: tenantId,
    status: evaluateStatus(row),
    source,
    signed_license_token: row.signed_license_token,
    algorithm: row.algorithm || null,
    license_key: row.license_key || null,
    start_date: row.start_date || null,
    end_date: row.end_date || null,
    term_name: row.term_name || null,
    academic_year: row.academic_year || null,
    max_students: row.max_students != null ? row.max_students : null,
    max_staff: row.max_staff != null ? row.max_staff : null,
  };
}

router.get('/current', async (req, res) => {
  try {
    const tenantId = readTenantId(req);

    // Supabase-first, exactly like the middleware. The UI uses this
    // endpoint to display the license and its source.
    let row = null;
    let source = 'none';
    if (SupabaseLicenseService.isConfigured()) {
      try {
        const supabaseRow = await SupabaseLicenseService.fetchActiveLicense(tenantId);
        if (supabaseRow && supabaseRow.signed_license_token) {
          row = supabaseRow;
          source = 'supabase';
        }
      } catch (err) {
        // Fall through to local SQLite.
        console.warn('[licensing/current] Supabase fetch failed:', err.message);
      }
    }
    if (!row) {
      row = getDb()
        .prepare(
          'SELECT * FROM tenant_licenses WHERE tenant_id = ? ORDER BY date(end_date) DESC, rowid DESC LIMIT 1'
        )
        .get(tenantId);
      if (row) source = 'local';
    }

    res.json(rowToResponse(tenantId, row, source));
  } catch (err) {
    console.error('LICENSING CURRENT ERROR:', err);
    res.status(500).json({ error: 'Internal Server Error', message: err.message });
  }
});

router.get('/public-key', (req, res) => {
  const publicKey = process.env.SUPERADMIN_PUBLIC_KEY || '';
  res.json({
    public_key: publicKey.replace(/\\n/g, '\n')
  });
});

function getArtifactEncryptionKey(tenantId) {
  const secret = process.env.LICENSE_ARTIFACT_SECRET || process.env.SUPERADMIN_PUBLIC_KEY || 'nextgen-lms-licensing-secret-2026';
  return crypto.createHash('sha256').update(`${secret}:${tenantId}`).digest();
}

function decryptArtifactPayload(envelope) {
  if (!envelope || !envelope.ciphertext || !envelope.iv || !envelope.auth_tag) {
    throw new Error('Invalid encrypted artifact package format');
  }

  const tenantId = envelope.tenant_id || 'default';
  const key = getArtifactEncryptionKey(tenantId);
  const iv = Buffer.from(envelope.iv, 'hex');
  const authTag = Buffer.from(envelope.auth_tag, 'hex');
  const ciphertext = Buffer.from(envelope.ciphertext, 'base64');

  const decipher = crypto.createDecipheriv('aes-256-gcm', key, iv);
  decipher.setAuthTag(authTag);

  const decrypted = Buffer.concat([decipher.update(ciphertext), decipher.final()]);
  return JSON.parse(decrypted.toString('utf8'));
}

/**
 * POST /api/license/ingest
 * Ingests and verifies a downloadable .lic.json artifact on the tenant edge.
 */
router.post('/ingest', async (req, res) => {
  try {
    let rawArtifact = req.body.artifact || req.body;
    if (!rawArtifact) {
      return res.status(400).json({ error: 'Missing license artifact payload' });
    }

    if (rawArtifact.encrypted) {
      try {
        rawArtifact = decryptArtifactPayload(rawArtifact);
      } catch (err) {
        return res.status(422).json({
          error: 'Artifact decryption / tamper check failed',
          details: 'Artifact ciphertext is corrupt or tampered with: ' + err.message
        });
      }
    }

    const licenseObj = rawArtifact.license || rawArtifact;
    const token = licenseObj.signed_license_token || rawArtifact.signed_license_token;
    if (!token) {
      return res.status(400).json({ error: 'Invalid artifact: missing signed_license_token' });
    }

    const publicKey = (process.env.SUPERADMIN_PUBLIC_KEY || '').replace(/\\n/g, '\n');
    if (!publicKey) {
      return res.status(500).json({ error: 'Tenant server missing SUPERADMIN_PUBLIC_KEY environment variable' });
    }

    let verifiedPayload;
    try {
      verifiedPayload = verifyEdDsaJwt(token, publicKey);
    } catch (err) {
      return res.status(422).json({
        error: 'Cryptographic signature verification failed',
        details: err.message
      });
    }

    const tenantId = resolveTenantId(req);
    const targetTenantId = verifiedPayload.sub || tenantId;

    const licenseId = licenseObj.id || `lic-ingested-${Date.now()}`;
    const licenseKey = licenseObj.license_key || verifiedPayload.license_key || `LIC-${verifiedPayload.term || 'TERM'}-${verifiedPayload.academic_year || '2026'}`;
    const termName = licenseObj.term_name || verifiedPayload.term || 'Term 1';
    const academicYear = licenseObj.academic_year || verifiedPayload.academic_year || '2026';
    const startDate = licenseObj.start_date || (verifiedPayload.nbf ? new Date(verifiedPayload.nbf * 1000).toISOString().slice(0, 10) : new Date().toISOString().slice(0, 10));
    const endDate = licenseObj.end_date || (verifiedPayload.exp ? new Date(verifiedPayload.exp * 1000).toISOString().slice(0, 10) : new Date().toISOString().slice(0, 10));
    const graceDays = licenseObj.grace_period_days ?? 7;
    const maxStudents = licenseObj.max_students ?? verifiedPayload.max_students ?? 1000;
    const maxStaff = licenseObj.max_staff ?? verifiedPayload.max_staff ?? 200;
    const status = licenseObj.status || verifiedPayload.status || 'active';
    const issuedBy = licenseObj.issued_by || rawArtifact.issued_by || 'Offline Artifact Ingestion';

    const dbInstance = getDb();
    dbInstance.prepare(`
      INSERT INTO tenant_licenses (
        id, tenant_id, license_key, signed_license_token, algorithm,
        term_name, academic_year, start_date, end_date, grace_period_days,
        max_students, max_staff, status, issued_by
      ) VALUES (?, ?, ?, ?, 'EdDSA', ?, ?, ?, ?, ?, ?, ?, ?, ?)
      ON CONFLICT(id) DO UPDATE SET
        license_key = excluded.license_key,
        signed_license_token = excluded.signed_license_token,
        term_name = excluded.term_name,
        academic_year = excluded.academic_year,
        start_date = excluded.start_date,
        end_date = excluded.end_date,
        grace_period_days = excluded.grace_period_days,
        max_students = excluded.max_students,
        max_staff = excluded.max_staff,
        status = excluded.status,
        issued_by = excluded.issued_by
    `).run(
      licenseId,
      targetTenantId,
      licenseKey,
      token,
      termName,
      academicYear,
      startDate,
      endDate,
      graceDays,
      maxStudents,
      maxStaff,
      status,
      issuedBy
    );

    // Evict old cache
    await LicenseCache.del(targetTenantId);

    // Attempt push to Supabase Cloud if configured & supported
    let cloudSynced = false;
    if (typeof SupabaseLicenseService.syncLicenseToSupabase === 'function' && SupabaseLicenseService.isConfigured()) {
      try {
        await SupabaseLicenseService.syncLicenseToSupabase({
          id: licenseId,
          tenant_id: targetTenantId,
          license_key: licenseKey,
          signed_license_token: token,
          algorithm: 'EdDSA',
          term_name: termName,
          academic_year: academicYear,
          start_date: startDate,
          end_date: endDate,
          grace_period_days: graceDays,
          max_students: maxStudents,
          max_staff: maxStaff,
          status
        });
        cloudSynced = true;
      } catch (e) {
        console.warn('[Ingestion] Supabase cloud push failed (offline):', e.message);
      }
    }

    return res.status(200).json({
      ok: true,
      message: 'License artifact verified, ingested, and activated successfully',
      status: 'ACTIVE',
      source: 'local_ingested',
      cloud_synced: cloudSynced,
      license: {
        id: licenseId,
        tenant_id: targetTenantId,
        license_key: licenseKey,
        term_name: termName,
        academic_year: academicYear,
        start_date: startDate,
        end_date: endDate,
        max_students: maxStudents,
        max_staff: maxStaff,
        status
      }
    });
  } catch (err) {
    console.error('LICENSING INGESTION ERROR:', err);
    return res.status(500).json({ error: 'Failed to ingest license artifact', details: err.message });
  }
});

router.post('/upload', (req, res, next) => {
  req.url = '/ingest';
  return router.handle(req, res, next);
});

module.exports = router;

