import * as React from 'react'
import { render, act } from '@testing-library/react'
import { PostHogProvider, PostHog } from '..'
import posthogJs from 'posthog-js'
import { setDefaultPostHogInstance } from '../posthog-default'

// Mock posthog-js
jest.mock('posthog-js', () => ({
    __esModule: true,
    default: {
        init: jest.fn(),
        set_config: jest.fn(),
        __loaded: false,
    },
}))

describe('PostHogProvider component', () => {
    beforeEach(() => {
        setDefaultPostHogInstance(posthogJs)
    })

    afterEach(() => {
        setDefaultPostHogInstance(undefined)
    })

    it('should render children components', () => {
        const posthog = {} as unknown as PostHog
        const { getByText } = render(
            <PostHogProvider client={posthog}>
                <div>Test</div>
            </PostHogProvider>
        )
        expect(getByText('Test')).toBeTruthy()
    })

    describe('when using apiKey initialization', () => {
        const apiKey = 'test-api-key'
        const initialOptions = { api_host: 'https://app.posthog.com' }
        const updatedOptions = { api_host: 'https://eu.posthog.com' }

        beforeEach(() => {
            jest.clearAllMocks()
        })

        it('does not initialize when apiKey is missing', () => {
            const consoleSpy = jest.spyOn(console, 'warn').mockImplementation()

            render(
                <PostHogProvider apiKey={undefined as any} options={initialOptions}>
                    <div>Test</div>
                </PostHogProvider>
            )

            expect(posthogJs.init).not.toHaveBeenCalled()
            expect(consoleSpy).toHaveBeenCalledWith(
                '[PostHog.js] No `apiKey` or `client` were provided to `PostHogProvider`. Using default global `window.posthog` instance. You must initialize it manually. This is not recommended behavior.'
            )

            consoleSpy.mockRestore()
        })

        it('should call set_config when options change', () => {
            const { rerender } = render(
                <PostHogProvider apiKey={apiKey} options={initialOptions}>
                    <div>Test</div>
                </PostHogProvider>
            )

            // First render should initialize
            expect(posthogJs.init).toHaveBeenCalledWith(apiKey, initialOptions)

            // Rerender with new options
            act(() => {
                rerender(
                    <PostHogProvider apiKey={apiKey} options={updatedOptions}>
                        <div>Test</div>
                    </PostHogProvider>
                )
            })

            // Should call set_config with new options
            expect(posthogJs.set_config).toHaveBeenCalledWith(updatedOptions)
        })

        it('should NOT call set_config when we pass new options that are the same as the previous options', () => {
            const { rerender } = render(
                <PostHogProvider apiKey={apiKey} options={initialOptions}>
                    <div>Test</div>
                </PostHogProvider>
            )

            // First render should initialize
            expect(posthogJs.init).toHaveBeenCalledWith(apiKey, initialOptions)

            // Rerender with new options
            const sameOptionsButDifferentReference = { ...initialOptions }
            act(() => {
                rerender(
                    <PostHogProvider apiKey={apiKey} options={sameOptionsButDifferentReference}>
                        <div>Test</div>
                    </PostHogProvider>
                )
            })

            // Should NOT call set_config
            expect(posthogJs.set_config).not.toHaveBeenCalled()
        })

        it('should warn when attempting to change apiKey', () => {
            const consoleSpy = jest.spyOn(console, 'warn').mockImplementation()
            const newApiKey = 'different-api-key'

            const { rerender } = render(
                <PostHogProvider apiKey={apiKey} options={initialOptions}>
                    <div>Test</div>
                </PostHogProvider>
            )

            // First render should initialize
            expect(posthogJs.init).toHaveBeenCalledWith(apiKey, initialOptions)

            // Rerender with new apiKey
            act(() => {
                rerender(
                    <PostHogProvider apiKey={newApiKey} options={initialOptions}>
                        <div>Test</div>
                    </PostHogProvider>
                )
            })

            // Should warn about apiKey change
            expect(consoleSpy).toHaveBeenCalledWith(
                expect.stringContaining('You have provided a different `apiKey` to `PostHogProvider`')
            )

            consoleSpy.mockRestore()
        })

        it('warns if posthogJs has been loaded elsewhere', () => {
            ;(posthogJs as any).__loaded = true

            const consoleSpy = jest.spyOn(console, 'warn').mockImplementation()
            render(
                <PostHogProvider apiKey={apiKey} options={initialOptions}>
                    <div>Test</div>
                </PostHogProvider>
            )

            expect(consoleSpy).toHaveBeenCalledWith(
                expect.stringContaining('`posthog` was already loaded elsewhere. This may cause issues.')
            )

            consoleSpy.mockRestore()
            ;(posthogJs as any).__loaded = false
        })
    })
})
