/**
 * EN: Pact consumer test — Order Service consuming Inventory Service.
 * VI: Pact consumer test — Order Service sử dụng Inventory Service.
 *
 * Boundary: order -> inventory
 * Contracts:
 *   1. GET /api/v1/inventory/check — check stock availability
 *   2. POST /api/v1/inventory/deduct — deduct stock on order confirmation
 */
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, integer, boolean } = MatchersV3;

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

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

const PRODUCT_ID = '550e8400-e29b-41d4-a716-446655440002';
const SHOP_ID = '550e8400-e29b-41d4-a716-446655440003';

// ---------------------------------------------------------------------------
// Consumer-side clients (mirrors InventoryServiceClient)
// ---------------------------------------------------------------------------
async function checkStock(baseUrl: string, productId: string, shopId: string, quantity: number) {
  const res = await fetch(
    `${baseUrl}/api/v1/inventory/check?productId=${productId}&shopId=${shopId}&quantity=${quantity}`
  );
  if (!res.ok) return { isAvailable: false };
  return res.json();
}

async function deductStock(baseUrl: string, productId: string, shopId: string, quantity: number) {
  const res = await fetch(`${baseUrl}/api/v1/inventory/deduct`, {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({ productId, shopId, quantity }),
  });
  return res.ok;
}

// ---------------------------------------------------------------------------
// Tests
// ---------------------------------------------------------------------------
describe('OrderService → InventoryService contract', () => {
  describe('GET /api/v1/inventory/check', () => {
    it('returns available=true when sufficient stock exists', async () => {
      await provider
        .addInteraction({
          states: [{ description: `product ${PRODUCT_ID} has 10 units in shop ${SHOP_ID}` }],
          uponReceiving: 'a stock availability check for quantity 3',
          withRequest: {
            method: 'GET',
            path: '/api/v1/inventory/check',
            query: { productId: PRODUCT_ID, shopId: SHOP_ID, quantity: '3' },
          },
          willRespondWith: {
            status: 200,
            headers: { 'Content-Type': 'application/json' },
            body: {
              isAvailable: boolean(true),
              availableQuantity: integer(10),
            },
          },
        })
        .executeTest(async (mockServer) => {
          const result = await checkStock(mockServer.url, PRODUCT_ID, SHOP_ID, 3);
          expect(result.isAvailable).toBe(true);
          expect(result.availableQuantity).toBeGreaterThanOrEqual(3);
        });
    });

    it('returns available=false when insufficient stock', async () => {
      await provider
        .addInteraction({
          states: [{ description: `product ${PRODUCT_ID} has only 1 unit in shop ${SHOP_ID}` }],
          uponReceiving: 'a stock availability check for quantity 10 when only 1 available',
          withRequest: {
            method: 'GET',
            path: '/api/v1/inventory/check',
            query: { productId: PRODUCT_ID, shopId: SHOP_ID, quantity: '10' },
          },
          willRespondWith: {
            status: 200,
            headers: { 'Content-Type': 'application/json' },
            body: {
              isAvailable: boolean(false),
              availableQuantity: integer(1),
            },
          },
        })
        .executeTest(async (mockServer) => {
          const result = await checkStock(mockServer.url, PRODUCT_ID, SHOP_ID, 10);
          expect(result.isAvailable).toBe(false);
        });
    });
  });

  describe('POST /api/v1/inventory/deduct', () => {
    it('deducts stock and returns 200 on success', async () => {
      await provider
        .addInteraction({
          states: [{ description: `product ${PRODUCT_ID} has sufficient stock in shop ${SHOP_ID}` }],
          uponReceiving: 'a request to deduct 2 units from inventory',
          withRequest: {
            method: 'POST',
            path: '/api/v1/inventory/deduct',
            headers: { 'Content-Type': 'application/json' },
            body: {
              productId: uuid(PRODUCT_ID),
              shopId: uuid(SHOP_ID),
              quantity: integer(2),
            },
          },
          willRespondWith: {
            status: 200,
            headers: { 'Content-Type': 'application/json' },
            body: {
              success: boolean(true),
              data: like({ remainingQuantity: integer(8) }),
            },
          },
        })
        .executeTest(async (mockServer) => {
          const success = await deductStock(mockServer.url, PRODUCT_ID, SHOP_ID, 2);
          expect(success).toBe(true);
        });
    });
  });
});
