import { describe, it, expect, vi, beforeEach } from 'vitest'
import { setActivePinia, createPinia } from 'pinia'
import { useUsersStore } from '@/stores/users'

vi.mock('@/api/client', () => ({
  get: vi.fn(),
  post: vi.fn(),
  patch: vi.fn(),
}))

import { get, post, patch } from '@/api/client'

const mockedGet = vi.mocked(get)
const mockedPost = vi.mocked(post)
const mockedPatch = vi.mocked(patch)

beforeEach(() => {
  setActivePinia(createPinia())
  vi.clearAllMocks()
})

describe('useUsersStore', () => {
  it('listUsers populates users', async () => {
    const users = [
      { id: 'u1', username: 'admin', fullName: 'Admin', role: 'ADMINISTRATOR' },
    ]
    mockedGet.mockResolvedValueOnce({
      success: true,
      statusCode: 200,
      data: users,
      error: null,
    })

    const store = useUsersStore()
    await store.listUsers()

    expect(mockedGet).toHaveBeenCalledWith('users', undefined)
    expect(store.users).toEqual(users)
    expect(store.loading).toBe(false)
  })

  it('listUsers passes role filter', async () => {
    mockedGet.mockResolvedValueOnce({
      success: true,
      statusCode: 200,
      data: [],
      error: null,
    })

    const store = useUsersStore()
    await store.listUsers('VERIFIER')

    expect(mockedGet).toHaveBeenCalledWith('users', { role: 'VERIFIER' })
  })

  it('createUser posts body and returns data', async () => {
    const created = {
      id: 'u2',
      username: 'clerk1',
      fullName: 'Clerk One',
      role: 'DATA_ENTRY_CLERK',
    }
    mockedPost.mockResolvedValueOnce({
      success: true,
      statusCode: 201,
      data: created,
      error: null,
    })

    const store = useUsersStore()
    const result = await store.createUser({
      username: 'clerk1',
      password: 'Password1',
      fullName: 'Clerk One',
      role: 'DATA_ENTRY_CLERK',
    })

    expect(mockedPost).toHaveBeenCalledWith('users', {
      username: 'clerk1',
      password: 'Password1',
      fullName: 'Clerk One',
      role: 'DATA_ENTRY_CLERK',
    })
    expect(result).toEqual(created)
  })

  it('updateUser patches and returns data', async () => {
    const updated = {
      id: 'u1',
      username: 'admin',
      fullName: 'New Name',
      role: 'ADMINISTRATOR',
    }
    mockedPatch.mockResolvedValueOnce({
      success: true,
      statusCode: 200,
      data: updated,
      error: null,
    })

    const store = useUsersStore()
    const result = await store.updateUser('u1', { fullName: 'New Name' })

    expect(mockedPatch).toHaveBeenCalledWith('users/u1', { fullName: 'New Name' })
    expect(result).toEqual(updated)
  })

  it('resetPassword posts new password', async () => {
    mockedPost.mockResolvedValueOnce('' as never)

    const store = useUsersStore()
    await store.resetPassword('u1', 'Password2')

    expect(mockedPost).toHaveBeenCalledWith('users/u1/reset-password', {
      newPassword: 'Password2',
    })
  })

  it('createUser surfaces API error message', async () => {
    mockedPost.mockRejectedValueOnce({
      response: { data: { error: { message: 'Username already taken', code: 'USERNAME_TAKEN' } } },
    })

    const store = useUsersStore()
    await expect(
      store.createUser({
        username: 'dup',
        password: 'Password1',
        fullName: 'Dup',
        role: 'VERIFIER',
      }),
    ).rejects.toThrow('Username already taken')
  })
})
