import { describe, it, expect, beforeEach, vi } from 'vitest'
import { createPinia, setActivePinia } from 'pinia'
import { useDictionaryGroupStore } from '@/store/modules/dictionaryGroup'
import { DictionaryScope } from '@/enums/Dictionary'

vi.mock('element-plus', () => ({
  ElMessage: {
    error: vi.fn(),
    success: vi.fn()
  }
}))

vi.mock('@/store/modules/user', () => ({
  useUserStore: () => ({
    info: { tenantId: '100' }
  })
}))

const getGroupsMock = vi.fn()
const createGroupMock = vi.fn()
const deleteGroupMock = vi.fn()
const updateGroupMock = vi.fn()
const getGroupByIdMock = vi.fn()

vi.mock('@/api/dictionary/group', () => ({
  getGroups: (...args: unknown[]) => getGroupsMock(...args),
  createGroup: (...args: unknown[]) => createGroupMock(...args),
  deleteGroup: (...args: unknown[]) => deleteGroupMock(...args),
  updateGroup: (...args: unknown[]) => updateGroupMock(...args),
  getGroupById: (...args: unknown[]) => getGroupByIdMock(...args)
}))

const createDeferred = <T>() => {
  let resolve: (value: T) => void
  let reject: (reason?: unknown) => void
  const promise = new Promise<T>((res, rej) => {
    resolve = res
    reject = rej
  })
  return { promise, resolve: resolve!, reject: reject! }
}

describe('dictionaryGroup store', () => {
  beforeEach(() => {
    setActivePinia(createPinia())
    vi.clearAllMocks()
  })

  it('fetchGroups updates state correctly', async () => {
    const store = useDictionaryGroupStore()
    const group: Api.Dictionary.DictionaryGroupDto = {
      id: '1',
      tenantId: '0',
      code: 'order_status',
      name: 'Order Status',
      scope: DictionaryScope.System,
      allowOverride: true,
      isEnabled: true,
      description: null,
      createdAt: new Date().toISOString(),
      updatedAt: null,
      rowVersion: '',
      items: []
    }
    getGroupsMock.mockResolvedValue({
      items: [group],
      page: 1,
      pageSize: 20,
      totalCount: 1,
      totalPages: 1
    })

    await store.fetchGroups(DictionaryScope.System, 1, 20)

    expect(store.groups).toEqual([group])
    expect(store.pagination.totalCount).toBe(1)
  })

  it('createGroup optimistic update and rollback on error', async () => {
    const store = useDictionaryGroupStore()
    const existing: Api.Dictionary.DictionaryGroupDto = {
      id: '2',
      tenantId: '0',
      code: 'payment_method',
      name: 'Payment Method',
      scope: DictionaryScope.System,
      allowOverride: true,
      isEnabled: true,
      description: null,
      createdAt: new Date().toISOString(),
      updatedAt: null,
      rowVersion: '',
      items: []
    }
    store.groups = [existing]

    const deferred = createDeferred<Api.Dictionary.DictionaryGroupDto>()
    createGroupMock.mockReturnValue(deferred.promise)

    const actionPromise = store.createGroup({
      code: 'shipping_method',
      name: 'Shipping Method',
      scope: DictionaryScope.System,
      allowOverride: false,
      description: null
    })

    expect(store.groups.length).toBe(2)
    expect(store.groups[0].code).toBe('shipping_method')

    deferred.reject(new Error('failed'))
    await actionPromise

    expect(store.groups).toEqual([existing])
  })

  it('deleteGroup removes from state', async () => {
    const store = useDictionaryGroupStore()
    const groupA: Api.Dictionary.DictionaryGroupDto = {
      id: '3',
      tenantId: '0',
      code: 'order_status',
      name: 'Order Status',
      scope: DictionaryScope.System,
      allowOverride: true,
      isEnabled: true,
      description: null,
      createdAt: new Date().toISOString(),
      updatedAt: null,
      rowVersion: '',
      items: []
    }
    const groupB: Api.Dictionary.DictionaryGroupDto = {
      id: '4',
      tenantId: '0',
      code: 'payment_method',
      name: 'Payment Method',
      scope: DictionaryScope.System,
      allowOverride: true,
      isEnabled: true,
      description: null,
      createdAt: new Date().toISOString(),
      updatedAt: null,
      rowVersion: '',
      items: []
    }
    store.groups = [groupA, groupB]
    store.currentGroup = groupA
    deleteGroupMock.mockResolvedValue(true)

    const result = await store.deleteGroup(groupA.id)

    expect(result).toBe(true)
    expect(store.groups).toEqual([groupB])
    expect(store.currentGroup).toBeNull()
  })
})
