import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest'
import { mount, VueWrapper } from '@vue/test-utils'
import { nextTick } from 'vue'
import LoginButton from '../shared/LoginButton.vue'

// Mock dependencies
vi.mock('vue-router', () => ({
  useRouter: vi.fn(() => ({ push: vi.fn() })),
}))

vi.mock('../../stores/auth', () => ({
  authenticateParent: vi.fn(),
  isParentAuthenticated: { value: false },
  isParentPersistent: { value: false },
  logoutParent: vi.fn(),
  logoutUser: vi.fn(),
  consumePendingReturnUrl: vi.fn(() => null),
  hasPendingReturnUrl: vi.fn(() => false),
  clearPendingReturnUrl: vi.fn(),
}))

vi.mock('@/common/imageCache', () => ({
  getCachedImageUrl: vi.fn(),
  getCachedImageBlob: vi.fn(),
}))

vi.mock('@/common/eventBus', () => ({
  eventBus: {
    on: vi.fn(),
    off: vi.fn(),
    emit: vi.fn(),
  },
}))

import { eventBus } from '@/common/eventBus'

describe('LoginButton', () => {
  let wrapper: VueWrapper<any>
  let mockFetch: any

  beforeEach(() => {
    vi.clearAllMocks()
    mockFetch = vi.fn()
    vi.stubGlobal('fetch', mockFetch)
  })

  afterEach(() => {
    if (wrapper) {
      wrapper.unmount()
    }
    vi.unstubAllGlobals()
  })

  describe('Event Listeners', () => {
    it('registers event listeners on mount', () => {
      mockFetch.mockResolvedValue({
        ok: true,
        json: () => Promise.resolve({ first_name: '', last_name: '', email: '', image_id: null }),
      })

      wrapper = mount(LoginButton)

      expect(eventBus.on).toHaveBeenCalledWith('open-login', expect.any(Function))
      expect(eventBus.on).toHaveBeenCalledWith('profile_updated', expect.any(Function))
    })

    it('unregisters event listeners on unmount', () => {
      mockFetch.mockResolvedValue({
        ok: true,
        json: () => Promise.resolve({ first_name: '', last_name: '', email: '', image_id: null }),
      })

      wrapper = mount(LoginButton)
      wrapper.unmount()

      expect(eventBus.off).toHaveBeenCalledWith('open-login', expect.any(Function))
      expect(eventBus.off).toHaveBeenCalledWith('profile_updated', expect.any(Function))
    })

    it('refetches profile when profile_updated event is received', async () => {
      mockFetch
        .mockResolvedValueOnce({
          ok: true,
          json: () => Promise.resolve({ first_name: '', last_name: '', email: '', image_id: null }),
        })
        .mockResolvedValueOnce({
          ok: true,
          json: () =>
            Promise.resolve({
              first_name: 'Updated',
              last_name: 'User',
              email: 'updated@example.com',
              image_id: 'new-image-id',
            }),
        })

      wrapper = mount(LoginButton)

      // Get the profile_updated callback
      const profileUpdatedCall = eventBus.on.mock.calls.find(
        (call) => call[0] === 'profile_updated',
      )
      const profileUpdatedCallback = profileUpdatedCall[1]

      // Call the callback
      await profileUpdatedCallback()

      // Check that fetch was called for profile
      expect(mockFetch).toHaveBeenCalledWith('/api/user/profile', { credentials: 'include' })
    })
  })
})
