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

const getMock = vi.fn()
const postMock = vi.fn()
const putMock = vi.fn()

vi.mock('@/lib/http/client', () => ({
  get: getMock,
  post: postMock,
  put: putMock,
}))

vi.mock('./users', () => ({
  getUserRoles: vi.fn().mockResolvedValue([{ id: 2, name: '管理员' }]),
}))

describe('profile service', () => {
  beforeEach(() => {
    getMock.mockReset()
    postMock.mockReset()
    putMock.mockReset()
  })

  it('gets current user profile with roles', async () => {
    getMock
      .mockResolvedValueOnce({ id: 1, username: 'admin', nickname: 'Admin' })
      .mockResolvedValueOnce([{ id: 2, name: '管理员' }])

    const { getCurrentProfile } = await import('./profile')
    const result = await getCurrentProfile(1)

    expect(getMock).toHaveBeenCalledWith('/auth/userinfo')
    expect(result).toEqual({
      user: { id: 1, username: 'admin', nickname: 'Admin' },
      roles: [{ id: 2, name: '管理员' }],
    })
  })

  it('updates user profile', async () => {
    const updateData = { nickname: 'New Nickname' }
    putMock.mockResolvedValue({ id: 1, ...updateData })

    const { updateProfile } = await import('./profile')
    const result = await updateProfile(1, updateData)

    expect(putMock).toHaveBeenCalledWith('/users/1', updateData)
    expect(result).toEqual({ id: 1, nickname: 'New Nickname' })
  })

  it('uploads avatar', async () => {
    const file = new File(['avatar'], 'avatar.png', { type: 'image/png' })
    const uploadResponse = {
      avatar_url: 'https://example.com/avatar.png',
      thumbnail: 'https://example.com/avatar_thumb.png',
      message: 'Upload success',
    }
    postMock.mockResolvedValue(uploadResponse)

    const { uploadAvatar } = await import('./profile')
    const result = await uploadAvatar(1, file)

    expect(postMock).toHaveBeenCalledWith('/users/1/avatar', expect.any(FormData))
    const payload = postMock.mock.calls[0][1] as FormData
    expect(payload.get('avatar')).toBe(file)
    expect(result).toEqual(uploadResponse)
  })

  it('updates password', async () => {
    putMock.mockResolvedValue(undefined)

    const { updatePassword } = await import('./profile')
    await updatePassword(1, {
      current_password: 'OldPass123',
      new_password: 'NewPass123',
      confirm_password: 'NewPass123',
    })

    expect(putMock).toHaveBeenCalledWith('/users/1/password', {
      current_password: 'OldPass123',
      new_password: 'NewPass123',
      confirm_password: 'NewPass123',
    })
  })

  it('gets TOTP status', async () => {
    getMock.mockResolvedValue({ totp_enabled: true })

    const { getTOTPStatus } = await import('./profile')
    const result = await getTOTPStatus()

    expect(getMock).toHaveBeenCalledWith('/auth/2fa/status')
    expect(result).toEqual({ totp_enabled: true })
  })

  it('gets TOTP setup data', async () => {
    const setupData = {
      secret: 'JBSWY3DPEHPK3PXP',
      qr_code_base64: 'data:image/png;base64,abc123',
      recovery_codes: ['code1', 'code2', 'code3'],
    }
    getMock.mockResolvedValue(setupData)

    const { getTOTPSetup } = await import('./profile')
    const result = await getTOTPSetup()

    expect(getMock).toHaveBeenCalledWith('/auth/2fa/setup')
    expect(result).toEqual(setupData)
  })

  it('enables TOTP', async () => {
    postMock.mockResolvedValue(undefined)

    const { enableTOTP } = await import('./profile')
    await enableTOTP('123456')

    expect(postMock).toHaveBeenCalledWith('/auth/2fa/enable', { code: '123456' })
  })

  it('disables TOTP', async () => {
    postMock.mockResolvedValue(undefined)

    const { disableTOTP } = await import('./profile')
    await disableTOTP('654321')

    expect(postMock).toHaveBeenCalledWith('/auth/2fa/disable', { code: '654321' })
  })
})
