import { renderHook, act, waitFor } from '@testing-library/react-native'
import { useChangePassword } from '@/hooks/use-change-password'
import { authClient } from '@/lib/auth'

// Mock authClient
jest.mock('@/lib/auth', () => ({
  authClient: {
    changePassword: jest.fn(),
  },
}))

describe('useChangePassword', () => {
  beforeEach(() => {
    jest.clearAllMocks()
  })

  afterEach(() => {
    jest.restoreAllMocks()
  })

  it('should change password successfully', async () => {
    const mockChangePassword = authClient.changePassword as jest.MockedFunction<typeof authClient.changePassword>
    mockChangePassword.mockResolvedValue({ error: null })

    const { result } = renderHook(() => useChangePassword())

    await act(async () => {
      await result.current.changePassword({
        oldPassword: 'oldPass123',
        newPassword: 'newPass123',
      })
    })

    expect(mockChangePassword).toHaveBeenCalledWith({
      oldPassword: 'oldPass123',
      newPassword: 'newPass123',
      revokeOtherSessions: true,
    })
    expect(result.current.error).toBeNull()
  })

  it('should validate old password is not empty', async () => {
    const { result } = renderHook(() => useChangePassword())

    await act(async () => {
      await result.current.changePassword({
        oldPassword: '',
        newPassword: 'newPass123',
      })
    })

    expect(result.current.error).toEqual({
      message: '旧密码不能为空',
    })
    expect(authClient.changePassword).not.toHaveBeenCalled()
  })

  it('should validate new password and confirm password match', async () => {
    const { result } = renderHook(() => useChangePassword())

    await act(async () => {
      await result.current.changePassword({
        oldPassword: 'oldPass123',
        newPassword: 'newPass123',
        confirmPassword: 'differentPass123',
      })
    })

    expect(result.current.error).toEqual({
      message: '新密码和确认密码不一致',
    })
    expect(authClient.changePassword).not.toHaveBeenCalled()
  })

  it('should validate new password length (minimum 6 characters)', async () => {
    const { result } = renderHook(() => useChangePassword())

    await act(async () => {
      await result.current.changePassword({
        oldPassword: 'oldPass123',
        newPassword: '12345',
      })
    })

    expect(result.current.error).toEqual({
      message: '新密码长度至少为6位',
    })
    expect(authClient.changePassword).not.toHaveBeenCalled()
  })

  it('should validate new password is different from old password', async () => {
    const { result } = renderHook(() => useChangePassword())

    await act(async () => {
      await result.current.changePassword({
        oldPassword: 'samePass123',
        newPassword: 'samePass123',
      })
    })

    expect(result.current.error).toEqual({
      message: '新密码不能与当前密码相同',
    })
    expect(authClient.changePassword).not.toHaveBeenCalled()
  })

  it('should handle API errors', async () => {
    const mockError = {
      status: 400,
      statusText: 'Bad Request',
      message: '旧密码错误',
    }

    const mockChangePassword = authClient.changePassword as jest.MockedFunction<typeof authClient.changePassword>
    mockChangePassword.mockRejectedValue(mockError)

    const { result } = renderHook(() => useChangePassword())

    await act(async () => {
      await result.current.changePassword({
        oldPassword: 'wrongPass',
        newPassword: 'newPass123',
      })
    })

    expect(result.current.error).toEqual(mockError)
  })

  it('should set loading state during password change', async () => {
    let resolveChangePassword: (value: any) => void
    const changePasswordPromise = new Promise((resolve) => {
      resolveChangePassword = resolve
    })

    const mockChangePassword = authClient.changePassword as jest.MockedFunction<typeof authClient.changePassword>
    mockChangePassword.mockReturnValue(changePasswordPromise)

    const { result } = renderHook(() => useChangePassword())

    act(() => {
      result.current.changePassword({
        oldPassword: 'oldPass123',
        newPassword: 'newPass123',
      })
    })

    expect(result.current.loading).toBe(true)

    await act(async () => {
      resolveChangePassword!({ error: null })
      await changePasswordPromise
    })

    expect(result.current.loading).toBe(false)
  })
})
