import { render, screen, waitFor } from '@testing-library/react'
import userEvent from '@testing-library/user-event'
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'

import { ContactBindingsSection } from './ContactBindingsSection'

const getCurrentProfileMock = vi.fn()
const sendEmailBindCodeMock = vi.fn()
const bindEmailMock = vi.fn()
const unbindPhoneMock = vi.fn()
const originalGetComputedStyle = window.getComputedStyle

vi.mock('@/services/profile', () => ({
  getCurrentProfile: (...args: unknown[]) => getCurrentProfileMock(...args),
}))

vi.mock('@/services/account-bindings', () => ({
  sendEmailBindCode: (...args: unknown[]) => sendEmailBindCodeMock(...args),
  bindEmail: (...args: unknown[]) => bindEmailMock(...args),
  bindPhone: vi.fn(),
  sendPhoneBindCode: vi.fn(),
  unbindEmail: vi.fn(),
  unbindPhone: (...args: unknown[]) => unbindPhoneMock(...args),
}))

describe('ContactBindingsSection', () => {
  afterEach(() => {
    vi.restoreAllMocks()
  })

  beforeEach(() => {
    getCurrentProfileMock.mockReset()
    sendEmailBindCodeMock.mockReset()
    bindEmailMock.mockReset()
    unbindPhoneMock.mockReset()

    getCurrentProfileMock.mockResolvedValue({
      user: {
        id: 1,
        username: 'admin',
        email: '',
        phone: '13812345678',
        nickname: 'Admin',
        avatar: '',
        gender: 0,
        birthday: '',
        region: '',
        bio: '',
        status: 1,
        last_login_at: '',
        last_login_ip: '',
        created_at: '',
        updated_at: '',
      },
      roles: [],
    })
    sendEmailBindCodeMock.mockResolvedValue(undefined)
    bindEmailMock.mockResolvedValue(undefined)
    unbindPhoneMock.mockResolvedValue(undefined)
    vi.spyOn(window, 'getComputedStyle').mockImplementation((element) => {
      return originalGetComputedStyle.call(window, element)
    })
  })

  it('sends a bind code and binds email after verification', async () => {
    const user = userEvent.setup()
    const refreshSessionUser = vi.fn().mockResolvedValue(undefined)

    render(
      <ContactBindingsSection
        userId={1}
        emailBindingEnabled
        phoneBindingEnabled
        refreshSessionUser={refreshSessionUser}
      />,
    )

    await waitFor(() => expect(screen.getByRole('button', { name: '绑定邮箱' })).toBeInTheDocument())

    await user.click(screen.getByRole('button', { name: '绑定邮箱' }))
    await user.type(screen.getByPlaceholderText('请输入新邮箱'), 'bind@example.com')
    await user.click(screen.getByRole('button', { name: '发送验证码' }))

    await waitFor(() => expect(sendEmailBindCodeMock).toHaveBeenCalledWith({ email: 'bind@example.com' }))

    await user.type(screen.getByPlaceholderText('请输入验证码'), '123456')
    await user.type(screen.getByPlaceholderText('建议填写当前密码'), 'SecurePass123')
    await user.click(screen.getByRole('button', { name: '确认绑定' }))

    await waitFor(() =>
      expect(bindEmailMock).toHaveBeenCalledWith({
        email: 'bind@example.com',
        code: '123456',
        current_password: 'SecurePass123',
        totp_code: undefined,
      }),
    )
    expect(refreshSessionUser).toHaveBeenCalled()
  })

  it('unbinds phone with the provided verification payload', async () => {
    const user = userEvent.setup()

    render(
      <ContactBindingsSection
        userId={1}
        emailBindingEnabled
        phoneBindingEnabled
        refreshSessionUser={vi.fn().mockResolvedValue(undefined)}
      />,
    )

    await waitFor(() => expect(screen.getByRole('button', { name: '解绑手机号' })).toBeInTheDocument())

    await user.click(screen.getByRole('button', { name: '解绑手机号' }))
    await user.type(screen.getByPlaceholderText('填写当前密码'), 'SecurePass123')
    await user.click(screen.getByRole('button', { name: '确认解绑' }))

    await waitFor(() =>
      expect(unbindPhoneMock).toHaveBeenCalledWith({
        current_password: 'SecurePass123',
        totp_code: undefined,
      }),
    )
  })
})
