import { describe, it, expect, beforeEach, vi } from 'vitest'
import { setActivePinia, createPinia } from 'pinia'

import { useUiStore } from './ui'

describe('useUiStore', () => {
  beforeEach(() => {
    setActivePinia(createPinia())
    vi.useFakeTimers()
  })

  describe('loading state', () => {
    it('starts with no loading', () => {
      /**
       * Test that the UI store initializes without loading state.
       *
       * The app should not show a loading overlay on startup.
       */
      const store = useUiStore()

      expect(store.isLoading).toBe(false)
      expect(store.loadingCount).toBe(0)
      expect(store.loadingMessage).toBeNull()
    })

    it('showLoading increments count', () => {
      /**
       * Test that showLoading enables the loading state.
       *
       * Components call showLoading to display a loading overlay
       * during async operations.
       */
      const store = useUiStore()

      store.showLoading()

      expect(store.isLoading).toBe(true)
      expect(store.loadingCount).toBe(1)
    })

    it('showLoading sets message', () => {
      /**
       * Test that showLoading can set a custom message.
       *
       * Different operations may want to show different
       * loading messages to the user.
       */
      const store = useUiStore()

      store.showLoading('Loading cards...')

      expect(store.loadingMessage).toBe('Loading cards...')
    })

    it('hideLoading decrements count', () => {
      /**
       * Test that hideLoading decrements the loading count.
       *
       * Multiple components may show loading simultaneously,
       * so we track count rather than boolean.
       */
      const store = useUiStore()

      store.showLoading()
      store.showLoading()
      store.hideLoading()

      expect(store.isLoading).toBe(true)
      expect(store.loadingCount).toBe(1)

      store.hideLoading()

      expect(store.isLoading).toBe(false)
      expect(store.loadingCount).toBe(0)
    })

    it('hideLoading clears message when count reaches zero', () => {
      /**
       * Test that the loading message is cleared when loading ends.
       *
       * Stale messages shouldn't persist after loading completes.
       */
      const store = useUiStore()

      store.showLoading('Loading...')
      store.hideLoading()

      expect(store.loadingMessage).toBeNull()
    })

    it('forceHideLoading resets all loading state', () => {
      /**
       * Test that forceHideLoading clears all loading state.
       *
       * This is useful for error recovery when loading count
       * gets out of sync.
       */
      const store = useUiStore()

      store.showLoading('Loading...')
      store.showLoading()
      store.showLoading()
      store.forceHideLoading()

      expect(store.isLoading).toBe(false)
      expect(store.loadingCount).toBe(0)
      expect(store.loadingMessage).toBeNull()
    })
  })

  describe('toast notifications', () => {
    it('starts with no toasts', () => {
      /**
       * Test that the UI store initializes without toasts.
       *
       * No toast notifications should be shown on startup.
       */
      const store = useUiStore()

      expect(store.toasts).toEqual([])
    })

    it('showToast adds a toast', () => {
      /**
       * Test that showToast creates a toast notification.
       *
       * Toasts are used to show success, error, and info
       * messages to the user.
       */
      const store = useUiStore()

      const id = store.showToast('success', 'Operation completed!')

      expect(store.toasts).toHaveLength(1)
      expect(store.toasts[0]).toMatchObject({
        id,
        type: 'success',
        message: 'Operation completed!',
      })
    })

    it('showToast auto-dismisses after duration', () => {
      /**
       * Test that toasts auto-dismiss after their duration.
       *
       * Toasts should disappear automatically so users don't
       * have to manually dismiss them.
       */
      const store = useUiStore()

      store.showToast('info', 'Auto dismiss test', 3000)

      expect(store.toasts).toHaveLength(1)

      vi.advanceTimersByTime(3000)

      expect(store.toasts).toHaveLength(0)
    })

    it('dismissToast removes a specific toast', () => {
      /**
       * Test that dismissToast removes a toast by ID.
       *
       * Users may want to manually dismiss toasts before
       * they auto-dismiss.
       */
      const store = useUiStore()

      const id1 = store.showToast('success', 'Toast 1', 0) // No auto-dismiss
      const id2 = store.showToast('error', 'Toast 2', 0)

      store.dismissToast(id1)

      expect(store.toasts).toHaveLength(1)
      expect(store.toasts[0].id).toBe(id2)
    })

    it('dismissAllToasts clears all toasts', () => {
      /**
       * Test that dismissAllToasts removes all toasts.
       *
       * Useful for clearing notifications when navigating
       * to a new page.
       */
      const store = useUiStore()

      store.showToast('success', 'Toast 1', 0)
      store.showToast('error', 'Toast 2', 0)
      store.showToast('info', 'Toast 3', 0)

      store.dismissAllToasts()

      expect(store.toasts).toHaveLength(0)
    })

    it('convenience methods create correct toast types', () => {
      /**
       * Test that convenience methods set correct toast types.
       *
       * showSuccess, showError, showWarning, showInfo should
       * create toasts with the appropriate type.
       */
      const store = useUiStore()

      store.showSuccess('Success!', 0)
      store.showError('Error!', 0)
      store.showWarning('Warning!', 0)
      store.showInfo('Info!', 0)

      expect(store.toasts[0].type).toBe('success')
      expect(store.toasts[1].type).toBe('error')
      expect(store.toasts[2].type).toBe('warning')
      expect(store.toasts[3].type).toBe('info')
    })
  })

  describe('modal state', () => {
    it('starts with closed modal', () => {
      /**
       * Test that the UI store initializes with no modal open.
       *
       * Modals should only open when explicitly triggered.
       */
      const store = useUiStore()

      expect(store.modal.isOpen).toBe(false)
      expect(store.modal.component).toBeNull()
      expect(store.modal.props).toEqual({})
    })

    it('openModal sets modal state', () => {
      /**
       * Test that openModal configures and shows a modal.
       *
       * The modal system uses component names and props to
       * dynamically render modal content.
       */
      const store = useUiStore()

      store.openModal('CardDetailModal', { cardId: '123' })

      expect(store.modal.isOpen).toBe(true)
      expect(store.modal.component).toBe('CardDetailModal')
      expect(store.modal.props).toEqual({ cardId: '123' })
    })

    it('closeModal resets modal state', () => {
      /**
       * Test that closeModal hides and resets the modal.
       *
       * After closing, modal state should be fully reset
       * for the next use.
       */
      const store = useUiStore()

      store.openModal('ConfirmModal', { message: 'Are you sure?' })
      store.closeModal()

      expect(store.modal.isOpen).toBe(false)
      expect(store.modal.component).toBeNull()
      expect(store.modal.props).toEqual({})
    })
  })
})
