/**
 * Integration tests for Tier management endpoints.
 * Uses a real Postgres test DB and Redis test instance.
 *
 * Routes covered:
 *   GET  /api/v1/tiers/status  — current tier, limits, and usage
 *   POST /api/v1/tiers/upgrade — initiate Stripe checkout for tier upgrade
 */

import crypto from 'crypto';
import request from 'supertest';
import { Application } from 'express';
import { v4 as uuidv4 } from 'uuid';
import { Pool } from 'pg';

const { privateKey, publicKey } = crypto.generateKeyPairSync('rsa', {
  modulusLength: 2048,
  publicKeyEncoding: { type: 'spki', format: 'pem' },
  privateKeyEncoding: { type: 'pkcs8', format: 'pem' },
});

process.env['DATABASE_URL'] =
  process.env['TEST_DATABASE_URL'] ??
  'postgresql://sentryagent:sentryagent@localhost:5432/sentryagent_idp_test';
process.env['REDIS_URL'] = process.env['TEST_REDIS_URL'] ?? 'redis://localhost:6379/1';
process.env['JWT_PRIVATE_KEY'] = privateKey;
process.env['JWT_PUBLIC_KEY'] = publicKey;
process.env['NODE_ENV'] = 'test';
process.env['DEFAULT_ORG_ID'] = 'org_system';
process.env['TIER_ENFORCEMENT'] = 'false';

import { createApp } from '../../src/app';
import { signToken } from '../../src/utils/jwt';
import { closePool } from '../../src/db/pool';
import { closeRedisClient } from '../../src/cache/redis';

const ORG_ID = uuidv4();
const AGENT_ID = uuidv4();

function makeToken(sub: string = AGENT_ID, scope = 'agents:read', orgId: string = ORG_ID): string {
  return signToken({ sub, client_id: sub, scope, organization_id: orgId, jti: uuidv4() }, privateKey);
}

describe('Tier Endpoints Integration Tests', () => {
  let app: Application;
  let pool: Pool;

  beforeAll(async () => {
    app = await createApp();
    pool = new Pool({ connectionString: process.env['DATABASE_URL'] });

    await pool.query(`
      CREATE TABLE IF NOT EXISTS organizations (
        organization_id VARCHAR(40) PRIMARY KEY,
        name VARCHAR(100) NOT NULL,
        plan VARCHAR(20) NOT NULL DEFAULT 'free',
        created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
        updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
      )
    `);

    await pool.query(`
      CREATE TABLE IF NOT EXISTS tenant_tiers (
        tenant_id VARCHAR(40) PRIMARY KEY REFERENCES organizations(organization_id),
        tier VARCHAR(20) NOT NULL DEFAULT 'free',
        created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
        updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
      )
    `);

    await pool.query(
      `INSERT INTO organizations (organization_id, name) VALUES ($1, $2) ON CONFLICT DO NOTHING`,
      [ORG_ID, 'Test Tier Org'],
    );

    await pool.query(
      `INSERT INTO tenant_tiers (tenant_id, tier) VALUES ($1, 'free') ON CONFLICT DO NOTHING`,
      [ORG_ID],
    );
  });

  afterAll(async () => {
    await pool.query(`DELETE FROM tenant_tiers WHERE tenant_id = $1`, [ORG_ID]);
    await pool.query(`DELETE FROM organizations WHERE organization_id = $1`, [ORG_ID]);
    await pool.end();
    await closePool();
    await closeRedisClient();
  });

  // ─── GET /tiers/status ───────────────────────────────────────────────────────

  describe('GET /api/v1/tiers/status', () => {
    it('should return 200 with tier status', async () => {
      const res = await request(app)
        .get('/api/v1/tiers/status')
        .set('Authorization', `Bearer ${makeToken()}`);

      expect(res.status).toBe(200);
      expect(res.body).toHaveProperty('tier');
    });

    it('should return 401 when no token provided', async () => {
      const res = await request(app).get('/api/v1/tiers/status');
      expect(res.status).toBe(401);
    });
  });

  // ─── POST /tiers/upgrade ─────────────────────────────────────────────────────

  describe('POST /api/v1/tiers/upgrade', () => {
    it('should return 401 when no token provided', async () => {
      const res = await request(app)
        .post('/api/v1/tiers/upgrade')
        .send({ targetTier: 'pro' });

      expect(res.status).toBe(401);
    });

    it('should return 422 when targetTier is missing', async () => {
      const res = await request(app)
        .post('/api/v1/tiers/upgrade')
        .set('Authorization', `Bearer ${makeToken()}`)
        .send({});

      expect([400, 422]).toContain(res.status);
    });

    it('should return 422 when targetTier is invalid', async () => {
      const res = await request(app)
        .post('/api/v1/tiers/upgrade')
        .set('Authorization', `Bearer ${makeToken()}`)
        .send({ targetTier: 'platinum' });

      expect([400, 422]).toContain(res.status);
    });
  });
});
