import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest'
import { mount, flushPromises } from '@vue/test-utils'
import PushOptIn from '../PushOptIn.vue'

const mockSubscribeToPush = vi.fn()
const mockGetPushPermissionState = vi.fn()

vi.mock('@/services/pushSubscription', () => ({
  subscribeToPush: () => mockSubscribeToPush(),
  getPushPermissionState: () => mockGetPushPermissionState(),
}))

function setupNotificationMock(permission: NotificationPermission) {
  Object.defineProperty(window, 'Notification', {
    writable: true,
    value: { permission },
  })
}

describe('PushOptIn', () => {
  afterEach(() => {
    vi.clearAllMocks()
  })

  describe('permission already granted on mount', () => {
    beforeEach(() => {
      setupNotificationMock('granted')
      mockSubscribeToPush.mockResolvedValue(true)
    })

    it('silently calls subscribeToPush without showing the banner', async () => {
      const wrapper = mount(PushOptIn)
      await flushPromises()

      expect(mockSubscribeToPush).toHaveBeenCalledOnce()
      expect(wrapper.find('.push-opt-in-banner').exists()).toBe(false)
    })
  })

  describe('permission default (not yet asked)', () => {
    beforeEach(() => {
      setupNotificationMock('default')
    })

    it('shows the opt-in banner with Enable button', async () => {
      const wrapper = mount(PushOptIn)
      await flushPromises()

      expect(wrapper.find('.push-opt-in-banner').exists()).toBe(true)
      expect(wrapper.find('.push-opt-in-btn').text()).toBe('Enable')
    })

    it('does NOT call subscribeToPush on mount', async () => {
      mount(PushOptIn)
      await flushPromises()

      expect(mockSubscribeToPush).not.toHaveBeenCalled()
    })

    it('calls subscribeToPush when Enable button is clicked', async () => {
      mockSubscribeToPush.mockResolvedValue(true)
      const wrapper = mount(PushOptIn)
      await flushPromises()

      await wrapper.find('.push-opt-in-btn').trigger('click')
      await flushPromises()

      expect(mockSubscribeToPush).toHaveBeenCalledOnce()
    })

    it('hides banner after Enable is clicked and subscription succeeds', async () => {
      mockSubscribeToPush.mockResolvedValue(true)
      const wrapper = mount(PushOptIn)
      await flushPromises()

      await wrapper.find('.push-opt-in-btn').trigger('click')
      await flushPromises()

      expect(wrapper.find('.push-opt-in-banner').exists()).toBe(false)
    })

    it('does NOT post subscription to backend when subscribeToPush returns false', async () => {
      mockSubscribeToPush.mockResolvedValue(false)
      const wrapper = mount(PushOptIn)
      await flushPromises()

      await wrapper.find('.push-opt-in-btn').trigger('click')
      await flushPromises()

      // Banner should still be visible (permission was denied)
      expect(wrapper.find('.push-opt-in-banner').exists()).toBe(true)
    })

    it('hides banner on dismiss without calling subscribeToPush', async () => {
      const wrapper = mount(PushOptIn)
      await flushPromises()

      await wrapper.find('.push-opt-in-dismiss').trigger('click')
      await flushPromises()

      expect(mockSubscribeToPush).not.toHaveBeenCalled()
      expect(wrapper.find('.push-opt-in-banner').exists()).toBe(false)
    })
  })

  describe('permission denied', () => {
    beforeEach(() => {
      setupNotificationMock('denied')
    })

    it('shows the blocked message banner', async () => {
      const wrapper = mount(PushOptIn)
      await flushPromises()

      expect(wrapper.find('.push-opt-in-banner').exists()).toBe(true)
      expect(wrapper.find('.push-opt-in-banner').text()).toContain('blocked')
    })

    it('does NOT show the Enable button when permission is denied', async () => {
      const wrapper = mount(PushOptIn)
      await flushPromises()

      expect(wrapper.find('.push-opt-in-btn').exists()).toBe(false)
    })

    it('does NOT call subscribeToPush on mount when already denied', async () => {
      mount(PushOptIn)
      await flushPromises()

      expect(mockSubscribeToPush).not.toHaveBeenCalled()
    })
  })
})
