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

const ORIGINAL_ENV = { ...process.env };

describe('trackTikTokLead', () => {
  beforeEach(() => {
    vi.resetModules();
    process.env = {
      ...ORIGINAL_ENV,
      TIKTOK_ACCESS_TOKEN: 'test-access-token',
      TIKTOK_PIXEL_CODE: 'PIXEL123',
    };
  });

  afterEach(() => {
    vi.restoreAllMocks();
    process.env = { ...ORIGINAL_ENV };
  });

  it('sends a deduplicated CompleteRegistration event to TikTok', async () => {
    const fetchMock = vi.fn().mockResolvedValue({
      ok: true,
      text: async () => JSON.stringify({ code: 0, message: 'OK' }),
    });
    vi.stubGlobal('fetch', fetchMock);

    const { trackTikTokLead } = await import('../tiktok');

    await trackTikTokLead({
      email: 'Fan@Example.com',
      eventId: 'signup-123',
      externalId: 'user-1',
      ip: '203.0.113.10',
      referrer: 'https://rainmakersports.app/landing',
      ttclid: 'ttclid-123',
      ttp: 'ttp-cookie',
      url: 'https://rainmakersports.app/signup',
      userAgent: 'Mozilla/5.0',
    });

    expect(fetchMock).toHaveBeenCalledTimes(1);
    const [url, options] = fetchMock.mock.calls[0] as [string, RequestInit];
    expect(url).toBe('https://business-api.tiktok.com/open_api/v1.3/event/track/');
    expect(options.headers).toMatchObject({
      'Access-Token': 'test-access-token',
      'Content-Type': 'application/json',
    });

    const body = JSON.parse(String(options.body));
    expect(body.event_source_id).toBe('PIXEL123');
    expect(body.event_source).toBe('web');
    expect(Array.isArray(body.data)).toBe(true);
    expect(body.data).toHaveLength(1);
    expect(body.data[0].event).toBe('CompleteRegistration');
    expect(body.data[0].event_id).toBe('signup-123');
    expect(body.data[0].ad.callback).toBe('ttclid-123');
    expect(body.data[0].user.ttp).toBe('ttp-cookie');
    expect(body.data[0].user.email).toMatch(/^[a-f0-9]{64}$/);
    expect(body.data[0].user.email).not.toBe('fan@example.com');
    expect(body.data[0].user.external_id).toMatch(/^[a-f0-9]{64}$/);
  });

  it('sends a Lead event for email capture submits', async () => {
    const fetchMock = vi.fn().mockResolvedValue({
      ok: true,
      text: async () => JSON.stringify({ code: 0, message: 'OK' }),
    });
    vi.stubGlobal('fetch', fetchMock);

    const { trackTikTokLeadSubmission } = await import('../tiktok');

    await trackTikTokLeadSubmission({
      email: 'lead@example.com',
      eventId: 'lead-123',
      externalId: 'user-lead-1',
      ttclid: 'ttclid-lead',
      ttp: 'ttp-lead',
      url: 'https://rainmakersports.app/signup',
    });

    const [, options] = fetchMock.mock.calls[0] as [string, RequestInit];
    const body = JSON.parse(String(options.body));
    expect(body.data[0].event).toBe('Lead');
    expect(body.data[0].event_id).toBe('lead-123');
    expect(body.data[0].user.email).toMatch(/^[a-f0-9]{64}$/);
    expect(body.data[0].properties).toEqual(expect.objectContaining({
      content_name: 'Rainmaker Sports lead',
      content_type: 'lead',
      status: 'submitted',
    }));
  });

  it('sends a SubmitForm event for form submissions', async () => {
    const fetchMock = vi.fn().mockResolvedValue({
      ok: true,
      text: async () => JSON.stringify({ code: 0, message: 'OK' }),
    });
    vi.stubGlobal('fetch', fetchMock);

    const { trackTikTokSubmitForm } = await import('../tiktok');

    await trackTikTokSubmitForm({
      email: 'form@example.com',
      eventId: 'submit-form-123',
      externalId: 'user-form-1',
      ttclid: 'ttclid-form',
      ttp: 'ttp-form',
      url: 'https://rainmakersports.app/signup',
    });

    const [, options] = fetchMock.mock.calls[0] as [string, RequestInit];
    const body = JSON.parse(String(options.body));
    expect(body.data[0].event).toBe('SubmitForm');
    expect(body.data[0].event_id).toBe('submit-form-123');
    expect(body.data[0].user.email).toMatch(/^[a-f0-9]{64}$/);
    expect(body.data[0].properties).toEqual(expect.objectContaining({
      content_name: 'Rainmaker Sports form',
      content_type: 'lead',
      status: 'submitted',
    }));
  });

  it('fails closed when the access token is missing', async () => {
    process.env.TIKTOK_ACCESS_TOKEN = '';
    const fetchMock = vi.fn();
    vi.stubGlobal('fetch', fetchMock);

    const { trackTikTokLead } = await import('../tiktok');

    await trackTikTokLead({
      email: 'fan@example.com',
    });

    expect(fetchMock).not.toHaveBeenCalled();
  });

  it('sends generic web events using external_id only when email is unavailable', async () => {
    const fetchMock = vi.fn().mockResolvedValue({
      ok: true,
      text: async () => JSON.stringify({ code: 0, message: 'OK' }),
    });
    vi.stubGlobal('fetch', fetchMock);

    const { trackTikTokWebEvent } = await import('../tiktok');

    await trackTikTokWebEvent({
      event: 'PageView',
      eventId: 'pageview-123',
      externalId: 'visitor-42',
      ip: '203.0.113.20',
      referrer: 'https://rainmakersports.app/pricing',
      ttclid: 'ttclid-pageview',
      ttp: 'ttp-cookie',
      url: 'https://rainmakersports.app/forecasts',
      userAgent: 'Mozilla/5.0',
    });

    const [, options] = fetchMock.mock.calls[0] as [string, RequestInit];
    const body = JSON.parse(String(options.body));
    expect(body.data[0].event).toBe('PageView');
    expect(body.data[0].event_id).toBe('pageview-123');
    expect(body.data[0].user.email).toBeUndefined();
    expect(body.data[0].user.external_id).toMatch(/^[a-f0-9]{64}$/);
  });
});
