import { renderHook } from '@testing-library/react';
import { VariantTypeEnum } from 'src/application/models';
import { EnviveMetricsEventName } from 'src/contexts/amplitudeContext';
import {
  FullPageSalesAgentVariantInfo,
  HomeVariantInfo,
  OtherVariantInfo,
  PDPPageVariantInfo,
  PLPPageVariantInfo,
  PageVariantInfo,
  VisitPageVariantInfo,
} from 'src/contexts/pageContext/types';
import { extractPageViewedContext, usePageViewedEvent } from '../usePageViewedEvent';

const mockTrackEvent = vi.fn();

vi.mock('src/contexts/amplitudeContext', async () => {
  const actual = await vi.importActual('src/contexts/amplitudeContext');
  return {
    ...actual,
    useAmplitude: () => ({
      trackEvent: mockTrackEvent,
    }),
  };
});

const mockUsePage = vi.fn();
vi.mock('src/contexts/pageContext', () => ({
  usePage: () => mockUsePage(),
}));

const mockUseAtomValue = vi.fn();
vi.mock('jotai', async () => {
  const actual = await vi.importActual('jotai');
  return {
    ...actual,
    useAtomValue: () => mockUseAtomValue(),
  };
});

describe('extractPageViewedContext', () => {
  it('should return pdp context', () => {
    const variant: PDPPageVariantInfo = {
      variantType: VariantTypeEnum.Pdp,
      productId: 'product-123',
      collections: [],
      numberOfReviews: 0,
      merchantTags: [],
      url: 'https://example.com/products/product-123',
    };
    expect(extractPageViewedContext(variant)).toEqual({
      page_type: 'pdp',
      page_id: 'product-123',
    });
  });

  it('should return plp context', () => {
    const variant: PLPPageVariantInfo = {
      variantType: VariantTypeEnum.Plp,
      plpId: 'collection-456',
      topCategory: 'shoes',
      url: 'https://example.com/collections/shoes',
    };
    expect(extractPageViewedContext(variant)).toEqual({
      page_type: 'plp',
      page_id: 'collection-456',
    });
  });

  it('should return homepage context', () => {
    const variant: HomeVariantInfo = {
      variantType: VariantTypeEnum.Home,
      url: 'https://example.com/',
    };
    expect(extractPageViewedContext(variant)).toEqual({
      page_type: 'homepage',
      page_id: 'https://example.com/',
    });
  });

  it('should return other context for Other variant', () => {
    const variant: OtherVariantInfo = {
      variantType: VariantTypeEnum.Other,
      url: 'https://example.com/about',
    };
    expect(extractPageViewedContext(variant)).toEqual({
      page_type: 'other',
      page_id: 'https://example.com/about',
    });
  });

  it('should return other context for PageVisit variant', () => {
    const variant: VisitPageVariantInfo = {
      variantType: VariantTypeEnum.PageVisit,
      url: 'https://example.com/contact',
    };
    expect(extractPageViewedContext(variant)).toEqual({
      page_type: 'other',
      page_id: 'https://example.com/contact',
    });
  });

  it('should return full_page_sales_agent context', () => {
    const variant: FullPageSalesAgentVariantInfo = {
      variantType: VariantTypeEnum.FullPageSalesAgent,
      url: 'https://example.com/agent',
    };
    expect(extractPageViewedContext(variant)).toEqual({
      page_type: 'full_page_sales_agent',
      page_id: 'https://example.com/agent',
    });
  });

  it('should return null for unknown variant type', () => {
    const variant = { variantType: 'unknown' } as unknown as PageVariantInfo;
    expect(extractPageViewedContext(variant)).toBeNull();
  });
});

describe('usePageViewedEvent', () => {
  beforeEach(() => {
    vi.clearAllMocks();
  });

  it('should not fire when still loading', () => {
    mockUsePage.mockReturnValue({
      variantInfo: {
        variantType: VariantTypeEnum.Pdp,
        productId: 'p1',
        collections: [],
        numberOfReviews: 0,
        merchantTags: [],
        url: '',
      },
      isSupported: true,
      isLoading: true,
    });
    mockUseAtomValue
      .mockReturnValueOnce({ variantId: 'v1', variant: 'pdp' })
      .mockReturnValueOnce(true);

    renderHook(() => usePageViewedEvent());
    expect(mockTrackEvent).not.toHaveBeenCalled();
  });

  it('should not fire when hasParsedVariantInfo is false', () => {
    mockUsePage.mockReturnValue({
      variantInfo: {
        variantType: VariantTypeEnum.Pdp,
        productId: 'p1',
        collections: [],
        numberOfReviews: 0,
        merchantTags: [],
        url: '',
      },
      isSupported: true,
      isLoading: false,
    });
    mockUseAtomValue
      .mockReturnValueOnce({ variantId: 'v1', variant: 'pdp' })
      .mockReturnValueOnce(false);

    renderHook(() => usePageViewedEvent());
    expect(mockTrackEvent).not.toHaveBeenCalled();
  });

  it('should not fire when pageVariantInfo is undefined', () => {
    mockUsePage.mockReturnValue({
      variantInfo: undefined,
      isSupported: false,
      isLoading: false,
    });
    mockUseAtomValue
      .mockReturnValueOnce({ variantId: 'v1', variant: 'pdp' })
      .mockReturnValueOnce(true);

    renderHook(() => usePageViewedEvent());
    expect(mockTrackEvent).not.toHaveBeenCalled();
  });

  it('should fire with correct props for pdp page', () => {
    mockUsePage.mockReturnValue({
      variantInfo: {
        variantType: VariantTypeEnum.Pdp,
        productId: 'product-123',
        collections: [],
        numberOfReviews: 5,
        merchantTags: [],
        url: 'https://example.com/products/product-123',
      },
      isSupported: true,
      isLoading: false,
    });
    mockUseAtomValue
      .mockReturnValueOnce({ variantId: 'variant-A', variant: 'pdp' })
      .mockReturnValueOnce(true);

    renderHook(() => usePageViewedEvent());

    expect(mockTrackEvent).toHaveBeenCalledTimes(1);
    expect(mockTrackEvent).toHaveBeenCalledWith({
      eventName: EnviveMetricsEventName.PageViewed,
      eventProps: {
        'context.page_type': 'pdp',
        'context.page_id': 'product-123',
        'context.supported': true,
        'context.ready': true,
        'context.page_variant_id': 'variant-A',
      },
    });
  });

  it('should fire only once even if dependencies change', () => {
    mockUsePage.mockReturnValue({
      variantInfo: {
        variantType: VariantTypeEnum.Pdp,
        productId: 'product-123',
        collections: [],
        numberOfReviews: 0,
        merchantTags: [],
        url: '',
      },
      isSupported: true,
      isLoading: false,
    });
    mockUseAtomValue
      .mockReturnValueOnce({ variantId: 'v1', variant: 'pdp' })
      .mockReturnValueOnce(true);

    const { rerender } = renderHook(() => usePageViewedEvent());

    mockUseAtomValue
      .mockReturnValueOnce({ variantId: 'v1', variant: 'pdp' })
      .mockReturnValueOnce(true);

    rerender();

    expect(mockTrackEvent).toHaveBeenCalledTimes(1);
  });

  it('should fire with full_page_sales_agent page type', () => {
    mockUsePage.mockReturnValue({
      variantInfo: {
        variantType: VariantTypeEnum.FullPageSalesAgent,
        url: 'https://example.com/agent',
      },
      isSupported: true,
      isLoading: false,
    });
    mockUseAtomValue
      .mockReturnValueOnce({ variantId: 'fpsa-variant', variant: 'full_page' })
      .mockReturnValueOnce(true);

    renderHook(() => usePageViewedEvent());

    expect(mockTrackEvent).toHaveBeenCalledTimes(1);
    expect(mockTrackEvent).toHaveBeenCalledWith({
      eventName: EnviveMetricsEventName.PageViewed,
      eventProps: {
        'context.page_type': 'full_page_sales_agent',
        'context.page_id': 'https://example.com/agent',
        'context.supported': true,
        'context.ready': true,
        'context.page_variant_id': 'fpsa-variant',
      },
    });
  });

  it('should set supported and ready to false when isSupported is false', () => {
    mockUsePage.mockReturnValue({
      variantInfo: {
        variantType: VariantTypeEnum.Pdp,
        productId: 'product-456',
        collections: [],
        numberOfReviews: 0,
        merchantTags: [],
        url: '',
      },
      isSupported: false,
      isLoading: false,
    });
    mockUseAtomValue
      .mockReturnValueOnce({ variantId: 'v2', variant: 'pdp' })
      .mockReturnValueOnce(true);

    renderHook(() => usePageViewedEvent());

    expect(mockTrackEvent).toHaveBeenCalledWith(
      expect.objectContaining({
        eventProps: expect.objectContaining({
          'context.supported': false,
          'context.ready': false,
        }),
      }),
    );
  });
});
