import { afterEach, describe, expect, it, vi } from 'vitest';
import { AlqoveClient } from '../../client';
import { createCheckinEndpoints } from '../checkin';

function mockFetchOk(json: unknown = { data: {} }) {
  const fetchMock = vi.fn(async () => ({
    ok: true,
    status: 200,
    json: async () => json,
  })) as unknown as typeof fetch;
  vi.stubGlobal('fetch', fetchMock);
  return fetchMock as unknown as ReturnType<typeof vi.fn>;
}

function call(fetchMock: ReturnType<typeof vi.fn>, i = 0) {
  const [url, init] = fetchMock.mock.calls[i];
  return {
    url: String(url),
    method: init.method as string,
    headers: init.headers as Record<string, string>,
    body: init.body ? JSON.parse(init.body as string) : undefined,
  };
}

const TOKEN = 'store-link-token';
const PAYLOAD = {
  phone: '5125551234',
  first_name: 'Ada',
  last_name: 'Lovelace',
  container_count: 3,
  container_description: 'two totes + a box',
  opt_loyalty: true,
  opt_txn: true,
  opt_promo: false,
};

describe('createCheckinEndpoints (Task 1)', () => {
  afterEach(() => {
    vi.unstubAllGlobals();
    vi.restoreAllMocks();
  });

  it('getBranding hits GET /v1/checkin/{token} with no auth', async () => {
    const fetchMock = mockFetchOk({ data: { store_name: 'Wax & Wane' } });
    const checkin = createCheckinEndpoints(new AlqoveClient({ baseUrl: 'http://api.test' }));

    await checkin.getBranding(TOKEN);

    const c = call(fetchMock);
    expect(c.method).toBe('GET');
    expect(c.url).toBe('http://api.test/v1/checkin/store-link-token');
    expect(c.headers['Authorization']).toBeUndefined();
  });

  it('submit puts the same idempotencyKey in BOTH the body and the Idempotency-Key header', async () => {
    const fetchMock = mockFetchOk({ data: { checkin_code: 'A7X-4421' } });
    const checkin = createCheckinEndpoints(new AlqoveClient({ baseUrl: 'http://api.test' }));

    await checkin.submit(TOKEN, PAYLOAD, {
      idempotencyKey: 'stable-key-abc',
      turnstileToken: 'ts-token',
    });

    const c = call(fetchMock);
    expect(c.method).toBe('POST');
    expect(c.url).toBe('http://api.test/v1/checkin/store-link-token/requests');
    expect(c.headers['Idempotency-Key']).toBe('stable-key-abc');
    expect(c.body.idempotency_key).toBe('stable-key-abc');
    expect(c.body.turnstile_token).toBe('ts-token');
    expect(c.body.phone).toBe('5125551234');
  });

  it('submit omits Authorization unless an authToken is supplied', async () => {
    const fetchMock = mockFetchOk();
    const checkin = createCheckinEndpoints(new AlqoveClient({ baseUrl: 'http://api.test' }));

    await checkin.submit(TOKEN, PAYLOAD, { idempotencyKey: 'k1', turnstileToken: 'ts' });

    expect(call(fetchMock).headers['Authorization']).toBeUndefined();
  });

  it('submit attaches Authorization: Bearer only when authToken is passed', async () => {
    const fetchMock = mockFetchOk();
    const checkin = createCheckinEndpoints(new AlqoveClient({ baseUrl: 'http://api.test' }));

    await checkin.submit(TOKEN, PAYLOAD, {
      idempotencyKey: 'k1',
      turnstileToken: 'ts',
      authToken: 'user-bearer',
    });

    expect(call(fetchMock).headers['Authorization']).toBe('Bearer user-bearer');
  });

  it('a retry with the same idempotencyKey re-sends the identical key (safe replay)', async () => {
    const fetchMock = mockFetchOk();
    const checkin = createCheckinEndpoints(new AlqoveClient({ baseUrl: 'http://api.test' }));

    const opts = { idempotencyKey: 'stable-key-abc', turnstileToken: 'ts' };
    await checkin.submit(TOKEN, PAYLOAD, opts);
    await checkin.submit(TOKEN, PAYLOAD, opts);

    expect(call(fetchMock, 0).headers['Idempotency-Key']).toBe('stable-key-abc');
    expect(call(fetchMock, 0).body.idempotency_key).toBe('stable-key-abc');
    expect(call(fetchMock, 1).headers['Idempotency-Key']).toBe('stable-key-abc');
    expect(call(fetchMock, 1).body.idempotency_key).toBe('stable-key-abc');
  });

  it('getStatus hits GET /v1/checkin/status/{token} with no auth', async () => {
    const fetchMock = mockFetchOk({ data: { status: 'remote_check_in' } });
    const checkin = createCheckinEndpoints(new AlqoveClient({ baseUrl: 'http://api.test' }));

    await checkin.getStatus('status-tok-xyz');

    const c = call(fetchMock);
    expect(c.method).toBe('GET');
    expect(c.url).toBe('http://api.test/v1/checkin/status/status-tok-xyz');
    expect(c.headers['Authorization']).toBeUndefined();
  });
});
