import { afterEach, describe, expect, it, vi } from 'vitest';
import {
  attachInteractionSession,
  sendInteractionMessage,
  stopInteractionSession,
} from './gateway-api.js';

const gateway = 'https://gateway.example.test';
const cookie = 'session=test';
const base = { agentName: 'Nova', correlationId: 'corr-1', sessionId: 'session-1' };

afterEach(() => vi.unstubAllGlobals());

/** Unit coverage: the TUI preserves a non-success gateway response in its CLI error. */
describe('interaction gateway error mapping', (): void => {
  it.each([
    {
      name: 'attach unauthorized',
      response: { status: 401, message: 'Invalid or expired session' },
      invoke: (): Promise<unknown> => attachInteractionSession(gateway, cookie, base),
      expected:
        'Failed to attach interaction session (401): {"message":"Invalid or expired session"}',
    },
    {
      name: 'send invalid request',
      response: { status: 403, message: 'Content and idempotency key are required' },
      invoke: (): Promise<unknown> =>
        sendInteractionMessage(gateway, cookie, {
          ...base,
          content: 'hello',
          idempotencyKey: 'message-1',
        }),
      expected:
        'Failed to send interaction message (403): {"message":"Content and idempotency key are required"}',
    },
    {
      name: 'stop forbidden',
      response: { status: 403, message: 'Runtime termination approval denied' },
      invoke: (): Promise<unknown> =>
        stopInteractionSession(gateway, cookie, { ...base, approvalRef: 'approval-1' }),
      expected:
        'Failed to stop interaction session (403): {"message":"Runtime termination approval denied"}',
    },
  ])(
    '$name preserves the typed gateway denial in the CLI error',
    async ({ response, invoke, expected }) => {
      vi.stubGlobal(
        'fetch',
        vi.fn(
          async () =>
            new Response(JSON.stringify({ message: response.message }), {
              status: response.status,
              headers: { 'Content-Type': 'application/json' },
            }),
        ),
      );

      await expect(invoke()).rejects.toThrow(expected);
    },
  );
});
