/**
 * EN: Pact consumer test — Merchant Service consuming IAM Service.
 * VI: Pact consumer test — Merchant Service sử dụng IAM Service.
 *
 * Boundary: merchant -> iam
 * Contracts:
 *   1. GET /api/v1/users/{userId} — resolve user/owner info during merchant onboarding
 *   2. POST /api/v1/rbac/check — permission check for merchant operations
 */
import { describe, it, expect } from 'vitest';
import { PactV3, MatchersV3 } from '@pact-foundation/pact';
import path from 'path';
import { fileURLToPath } from 'url';

const { like, string, uuid, boolean, eachLike } = MatchersV3;

const __dirname = path.dirname(fileURLToPath(import.meta.url));
const PACT_DIR = path.resolve(__dirname, '../../pacts');

const provider = new PactV3({
  consumer: 'MerchantService',
  provider: 'IamService',
  dir: PACT_DIR,
  logLevel: 'warn',
});

const USER_ID = '550e8400-e29b-41d4-a716-446655440020';
const BEARER_TOKEN = 'Bearer test-jwt-token';

// ---------------------------------------------------------------------------
// Consumer-side client
// ---------------------------------------------------------------------------
async function getUserById(baseUrl: string, userId: string, token: string) {
  const res = await fetch(`${baseUrl}/api/v1/users/${userId}`, {
    headers: { Authorization: token },
  });
  if (!res.ok) return null;
  return res.json();
}

async function checkPermission(
  baseUrl: string,
  userId: string,
  resource: string,
  action: string,
  token: string
) {
  const res = await fetch(`${baseUrl}/api/v1/rbac/check`, {
    method: 'POST',
    headers: { 'Content-Type': 'application/json', Authorization: token },
    body: JSON.stringify({ userId, resource, action }),
  });
  if (!res.ok) return { allowed: false };
  return res.json();
}

// ---------------------------------------------------------------------------
// Tests
// ---------------------------------------------------------------------------
describe('MerchantService → IamService contract', () => {
  describe('GET /api/v1/users/{userId}', () => {
    it('returns user info for existing active user', async () => {
      await provider
        .addInteraction({
          states: [{ description: `user ${USER_ID} is active` }],
          uponReceiving: 'a request to get user by ID with valid token',
          withRequest: {
            method: 'GET',
            path: `/api/v1/users/${USER_ID}`,
            headers: { Authorization: BEARER_TOKEN },
          },
          willRespondWith: {
            status: 200,
            headers: { 'Content-Type': 'application/json' },
            body: {
              success: boolean(true),
              data: like({
                id: uuid(USER_ID),
                email: string('owner@goodgo.vn'),
                role: string('ADMIN'),
                isActive: boolean(true),
              }),
            },
          },
        })
        .executeTest(async (mockServer) => {
          const result = await getUserById(mockServer.url, USER_ID, BEARER_TOKEN);
          expect(result).not.toBeNull();
          expect(result.success).toBe(true);
          expect(result.data.id).toBe(USER_ID);
          expect(result.data.isActive).toBe(true);
        });
    });

    it('returns 401 when token is missing', async () => {
      await provider
        .addInteraction({
          states: [{ description: 'authentication is required' }],
          uponReceiving: 'a request to get user without authorization token',
          withRequest: {
            method: 'GET',
            path: `/api/v1/users/${USER_ID}`,
          },
          willRespondWith: {
            status: 401,
            headers: { 'Content-Type': 'application/json' },
            body: {
              success: boolean(false),
              error: like({ code: string('UNAUTHORIZED') }),
            },
          },
        })
        .executeTest(async (mockServer) => {
          const result = await getUserById(mockServer.url, USER_ID, '');
          expect(result).toBeNull();
        });
    });
  });

  describe('POST /api/v1/rbac/check', () => {
    it('returns allowed=true for authorized merchant operation', async () => {
      await provider
        .addInteraction({
          states: [{ description: `user ${USER_ID} has merchants:write permission` }],
          uponReceiving: 'a permission check for merchants:write',
          withRequest: {
            method: 'POST',
            path: '/api/v1/rbac/check',
            headers: { 'Content-Type': 'application/json', Authorization: BEARER_TOKEN },
            body: {
              userId: uuid(USER_ID),
              resource: string('merchants'),
              action: string('write'),
            },
          },
          willRespondWith: {
            status: 200,
            headers: { 'Content-Type': 'application/json' },
            body: {
              allowed: boolean(true),
            },
          },
        })
        .executeTest(async (mockServer) => {
          const result = await checkPermission(
            mockServer.url,
            USER_ID,
            'merchants',
            'write',
            BEARER_TOKEN
          );
          expect(result.allowed).toBe(true);
        });
    });
  });
});
