import { afterEach, describe, expect, it, vi } from 'vitest';

import {
  listChannelConnections,
  getChannelConnectorSession,
  listChannelConnectors,
  startChannelConnectorSession,
} from '@/lib/api';

const originalFetch = globalThis.fetch;

afterEach(() => {
  globalThis.fetch = originalFetch;
  if (typeof localStorage !== 'undefined') {
    localStorage.clear();
  }
  vi.restoreAllMocks();
});

function mockJsonResponse(body: unknown) {
  return Promise.resolve({
    ok: true,
    json: () => Promise.resolve(body),
  } as Response);
}

function firstFetchCall(fetchMock: any): [unknown, RequestInit] {
  return fetchMock.mock.calls[0] as [unknown, RequestInit];
}

describe('channel connector api', () => {
  it('lists available channel connectors', async () => {
    const fetchMock = vi.fn(() => mockJsonResponse([{ kind: 'weixin', displayName: 'Weixin' }]));
    globalThis.fetch = fetchMock as typeof fetch;

    const connectors = await listChannelConnectors();

    expect(connectors).toEqual([{ kind: 'weixin', displayName: 'Weixin' }]);
    expect(String(firstFetchCall(fetchMock)[0])).toMatch(/\/api\/channel-connectors$/);
  });

  it('lists existing channel connections', async () => {
    const fetchMock = vi.fn(() =>
      mockJsonResponse([{ connection_id: 'conn_1', channel_id: 'weixin-1', kind: 'weixin', status: 'connected' }])
    );
    globalThis.fetch = fetchMock as typeof fetch;

    const connections = await listChannelConnections();

    expect(connections[0].status).toBe('connected');
    expect(String(firstFetchCall(fetchMock)[0])).toMatch(/\/api\/channel-connections$/);
  });

  it('starts a connector session with options', async () => {
    const fetchMock = vi.fn(() =>
      mockJsonResponse({
        session: { sessionId: 'cs_1', kind: 'weixin', status: 'qr_ready' },
        connection: { connection_id: 'conn_1', kind: 'weixin', status: 'pairing' },
      })
    );
    globalThis.fetch = fetchMock as typeof fetch;

    const response = await startChannelConnectorSession({
      kind: 'weixin',
      displayName: 'Weixin Main',
      options: { mode: 'qr' },
    });

    expect(response.session.sessionId).toBe('cs_1');
    const [, request] = firstFetchCall(fetchMock);
    expect(String(firstFetchCall(fetchMock)[0])).toMatch(/\/api\/channel-connector-sessions$/);
    expect(request).toEqual(
      expect.objectContaining({
        method: 'POST',
        body: JSON.stringify({ kind: 'weixin', displayName: 'Weixin Main', options: { mode: 'qr' } }),
      })
    );
  });

  it('polls a connector session by id', async () => {
    const fetchMock = vi.fn(() =>
      mockJsonResponse({
        session: { sessionId: 'cs_1', kind: 'weixin', status: 'connected' },
        connection: { connection_id: 'conn_1', kind: 'weixin', status: 'connected' },
      })
    );
    globalThis.fetch = fetchMock as typeof fetch;

    const response = await getChannelConnectorSession('cs_1');

    expect(response.connection?.status).toBe('connected');
    expect(String(firstFetchCall(fetchMock)[0])).toMatch(/\/api\/channel-connector-sessions\/cs_1$/);
  });
});
