/**
 * UI Store Tests
 *
 * Tests for toast notifications, modal stack management, and UI state.
 */

import { describe, it, expect, beforeEach, vi, afterEach } from 'vitest'
import { setActivePinia, createPinia } from 'pinia'
import { useUiStore } from '~/store/ui'

describe('useUiStore', () => {
  beforeEach(() => {
    // Ensure process.env exists before creating Pinia
    if (!process.env) {
      (process as any).env = {}
    }
    process.env.NODE_ENV = 'test'

    // Create fresh Pinia instance for each test
    setActivePinia(createPinia())
    vi.useFakeTimers()
  })

  afterEach(() => {
    vi.restoreAllMocks()
    vi.useRealTimers()
  })

  describe('initialization', () => {
    it('initializes with empty state', () => {
      const store = useUiStore()

      expect(store.toasts).toEqual([])
      expect(store.modals).toEqual([])
      expect(store.isSidebarOpen).toBe(false)
      expect(store.isFullscreen).toBe(false)
      expect(store.globalLoading).toBe(false)
      expect(store.globalLoadingMessage).toBeNull()
    })

    it('has correct computed properties on init', () => {
      const store = useUiStore()

      expect(store.hasToasts).toBe(false)
      expect(store.hasModals).toBe(false)
      expect(store.currentModal).toBeNull()
    })
  })

  describe('toast management', () => {
    it('adds toast with showToast', () => {
      const store = useUiStore()

      const id = store.showToast('Test message', 'info', 5000)

      expect(store.toasts.length).toBe(1)
      expect(store.toasts[0]).toMatchObject({
        id,
        type: 'info',
        message: 'Test message',
        duration: 5000,
      })
      expect(store.hasToasts).toBe(true)
    })

    it('adds success toast with showSuccess', () => {
      const store = useUiStore()

      const id = store.showSuccess('Success!')

      expect(store.toasts.length).toBe(1)
      expect(store.toasts[0].type).toBe('success')
      expect(store.toasts[0].message).toBe('Success!')
      expect(store.toasts[0].duration).toBe(5000) // default
    })

    it('adds error toast with showError', () => {
      const store = useUiStore()

      const id = store.showError('Error occurred')

      expect(store.toasts.length).toBe(1)
      expect(store.toasts[0].type).toBe('error')
      expect(store.toasts[0].message).toBe('Error occurred')
      expect(store.toasts[0].duration).toBe(7000) // default for errors
    })

    it('adds warning toast with showWarning', () => {
      const store = useUiStore()

      const id = store.showWarning('Warning!')

      expect(store.toasts.length).toBe(1)
      expect(store.toasts[0].type).toBe('warning')
      expect(store.toasts[0].duration).toBe(6000) // default for warnings
    })

    it('adds info toast with showInfo', () => {
      const store = useUiStore()

      const id = store.showInfo('Info message')

      expect(store.toasts.length).toBe(1)
      expect(store.toasts[0].type).toBe('info')
      expect(store.toasts[0].duration).toBe(5000)
    })

    it('auto-removes toast after duration', () => {
      const store = useUiStore()

      store.showToast('Auto-remove', 'info', 1000)

      expect(store.toasts.length).toBe(1)

      // Fast-forward time
      vi.advanceTimersByTime(1000)

      expect(store.toasts.length).toBe(0)
    })

    it('does not auto-remove toast with duration 0', () => {
      const store = useUiStore()

      store.showToast('Persistent', 'info', 0)

      expect(store.toasts.length).toBe(1)

      // Fast-forward time
      vi.advanceTimersByTime(10000)

      // Should still be there
      expect(store.toasts.length).toBe(1)
    })

    it('removes specific toast by ID', () => {
      const store = useUiStore()

      const id1 = store.showToast('Toast 1', 'info', 0)
      const id2 = store.showToast('Toast 2', 'info', 0)
      const id3 = store.showToast('Toast 3', 'info', 0)

      expect(store.toasts.length).toBe(3)

      store.removeToast(id2)

      expect(store.toasts.length).toBe(2)
      expect(store.toasts.find(t => t.id === id2)).toBeUndefined()
      expect(store.toasts.find(t => t.id === id1)).toBeDefined()
      expect(store.toasts.find(t => t.id === id3)).toBeDefined()
    })

    it('clears all toasts', () => {
      const store = useUiStore()

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

      expect(store.toasts.length).toBe(3)

      store.clearToasts()

      expect(store.toasts.length).toBe(0)
      expect(store.hasToasts).toBe(false)
    })

    it('supports toast with action callback', () => {
      const store = useUiStore()
      const actionCallback = vi.fn()

      const id = store.showToast('Toast with action', 'info', 0, {
        label: 'Undo',
        callback: actionCallback,
      })

      expect(store.toasts[0].action).toBeDefined()
      expect(store.toasts[0].action?.label).toBe('Undo')

      // Simulate action click
      store.toasts[0].action?.callback()

      expect(actionCallback).toHaveBeenCalledOnce()
    })
  })

  describe('modal management', () => {
    it('opens modal', () => {
      const store = useUiStore()

      const id = store.openModal('SubstitutionModal', { teamId: 1 })

      expect(store.modals.length).toBe(1)
      expect(store.modals[0]).toMatchObject({
        id,
        component: 'SubstitutionModal',
        props: { teamId: 1 },
      })
      expect(store.hasModals).toBe(true)
      expect(store.currentModal).toEqual(store.modals[0])
    })

    it('supports modal stack (LIFO)', () => {
      const store = useUiStore()

      const id1 = store.openModal('Modal1')
      const id2 = store.openModal('Modal2')
      const id3 = store.openModal('Modal3')

      expect(store.modals.length).toBe(3)
      expect(store.currentModal?.component).toBe('Modal3') // Last opened is current
    })

    it('closes current modal (top of stack)', () => {
      const store = useUiStore()

      store.openModal('Modal1')
      store.openModal('Modal2')
      store.openModal('Modal3')

      expect(store.modals.length).toBe(3)

      store.closeModal()

      expect(store.modals.length).toBe(2)
      expect(store.currentModal?.component).toBe('Modal2')
    })

    it('calls onClose callback when closing modal', () => {
      const store = useUiStore()
      const onCloseSpy = vi.fn()

      store.openModal('TestModal', {}, onCloseSpy)

      expect(store.modals.length).toBe(1)

      store.closeModal()

      expect(onCloseSpy).toHaveBeenCalledOnce()
      expect(store.modals.length).toBe(0)
    })

    it('closes specific modal by ID', () => {
      const store = useUiStore()

      const id1 = store.openModal('Modal1')
      const id2 = store.openModal('Modal2')
      const id3 = store.openModal('Modal3')

      expect(store.modals.length).toBe(3)

      store.closeModalById(id2)

      expect(store.modals.length).toBe(2)
      expect(store.modals.find(m => m.id === id2)).toBeUndefined()
      expect(store.modals.find(m => m.id === id1)).toBeDefined()
      expect(store.modals.find(m => m.id === id3)).toBeDefined()
    })

    it('calls onClose when closing modal by ID', () => {
      const store = useUiStore()
      const onCloseSpy = vi.fn()

      const id = store.openModal('TestModal', {}, onCloseSpy)

      store.closeModalById(id)

      expect(onCloseSpy).toHaveBeenCalledOnce()
    })

    it('closes all modals', () => {
      const store = useUiStore()
      const onClose1 = vi.fn()
      const onClose2 = vi.fn()
      const onClose3 = vi.fn()

      store.openModal('Modal1', {}, onClose1)
      store.openModal('Modal2', {}, onClose2)
      store.openModal('Modal3', {}, onClose3)

      expect(store.modals.length).toBe(3)

      store.closeAllModals()

      expect(store.modals.length).toBe(0)
      expect(store.hasModals).toBe(false)
      expect(store.currentModal).toBeNull()

      // All onClose callbacks should be called
      expect(onClose1).toHaveBeenCalledOnce()
      expect(onClose2).toHaveBeenCalledOnce()
      expect(onClose3).toHaveBeenCalledOnce()
    })
  })

  describe('UI state management', () => {
    it('toggles sidebar', () => {
      const store = useUiStore()

      expect(store.isSidebarOpen).toBe(false)

      store.toggleSidebar()
      expect(store.isSidebarOpen).toBe(true)

      store.toggleSidebar()
      expect(store.isSidebarOpen).toBe(false)
    })

    it('sets sidebar state directly', () => {
      const store = useUiStore()

      store.setSidebarOpen(true)
      expect(store.isSidebarOpen).toBe(true)

      store.setSidebarOpen(false)
      expect(store.isSidebarOpen).toBe(false)
    })

    it('sets fullscreen state', () => {
      const store = useUiStore()

      store.setFullscreen(true)
      expect(store.isFullscreen).toBe(true)

      store.setFullscreen(false)
      expect(store.isFullscreen).toBe(false)
    })

    it('shows loading overlay with message', () => {
      const store = useUiStore()

      store.showLoading('Processing...')

      expect(store.globalLoading).toBe(true)
      expect(store.globalLoadingMessage).toBe('Processing...')
    })

    it('shows loading overlay without message', () => {
      const store = useUiStore()

      store.showLoading()

      expect(store.globalLoading).toBe(true)
      expect(store.globalLoadingMessage).toBeNull()
    })

    it('hides loading overlay', () => {
      const store = useUiStore()

      store.showLoading('Loading...')
      expect(store.globalLoading).toBe(true)

      store.hideLoading()

      expect(store.globalLoading).toBe(false)
      expect(store.globalLoadingMessage).toBeNull()
    })
  })

  describe('edge cases', () => {
    it('handles removing non-existent toast gracefully', () => {
      const store = useUiStore()

      store.showToast('Toast', 'info', 0)
      expect(store.toasts.length).toBe(1)

      // Try to remove non-existent toast
      store.removeToast('non-existent-id')

      // Should not crash, toast count unchanged
      expect(store.toasts.length).toBe(1)
    })

    it('handles closing non-existent modal gracefully', () => {
      const store = useUiStore()

      store.openModal('Modal1')
      expect(store.modals.length).toBe(1)

      // Try to close non-existent modal
      store.closeModalById('non-existent-id')

      // Should not crash, modal count unchanged
      expect(store.modals.length).toBe(1)
    })

    it('handles closing modal when stack is empty', () => {
      const store = useUiStore()

      expect(store.modals.length).toBe(0)

      // Should not crash
      expect(() => store.closeModal()).not.toThrow()
      expect(store.modals.length).toBe(0)
    })

    it('generates unique IDs for toasts', () => {
      const store = useUiStore()

      const id1 = store.showToast('Toast 1', 'info', 0)
      const id2 = store.showToast('Toast 2', 'info', 0)
      const id3 = store.showToast('Toast 3', 'info', 0)

      // All IDs should be unique
      expect(new Set([id1, id2, id3]).size).toBe(3)
    })

    it('generates unique IDs for modals', () => {
      const store = useUiStore()

      const id1 = store.openModal('Modal1')
      const id2 = store.openModal('Modal2')
      const id3 = store.openModal('Modal3')

      // All IDs should be unique
      expect(new Set([id1, id2, id3]).size).toBe(3)
    })
  })
})
