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 { ProfileSecurityPage } from './ProfileSecurityPage'

const useAuthMock = vi.fn()
const getAuthCapabilitiesMock = vi.fn()
const listSocialAccountsMock = vi.fn()
const startSocialBindingMock = vi.fn()
const unbindSocialAccountMock = vi.fn()
const getTOTPStatusMock = vi.fn()
const listDevicesMock = vi.fn()
const listMyLoginLogsMock = vi.fn()
const listMyOperationLogsMock = vi.fn()
const assignMock = vi.fn()
const originalGetComputedStyle = window.getComputedStyle

vi.mock('@/app/providers/auth-context', () => ({
  useAuth: () => useAuthMock(),
}))

vi.mock('@/services/auth', () => ({
  getAuthCapabilities: () => getAuthCapabilitiesMock(),
}))

vi.mock('@/services/social-accounts', () => ({
  listSocialAccounts: () => listSocialAccountsMock(),
  startSocialBinding: (payload: unknown) => startSocialBindingMock(payload),
  unbindSocialAccount: (provider: string, payload: unknown) => unbindSocialAccountMock(provider, payload),
}))

vi.mock('@/services/profile', () => ({
  disableTOTP: vi.fn(),
  enableTOTP: vi.fn(),
  getTOTPSetup: vi.fn(),
  getTOTPStatus: () => getTOTPStatusMock(),
  updatePassword: vi.fn(),
  uploadAvatar: vi.fn(),
}))

vi.mock('@/services/devices', () => ({
  deleteDevice: vi.fn(),
  listDevices: () => listDevicesMock(),
  updateDeviceStatus: vi.fn(),
}))

vi.mock('@/services/login-logs', () => ({
  listMyLoginLogs: () => listMyLoginLogsMock(),
}))

vi.mock('@/services/operation-logs', () => ({
  listMyOperationLogs: () => listMyOperationLogsMock(),
}))

vi.mock('./ContactBindingsSection', () => ({
  ContactBindingsSection: () => <div data-testid="contact-bindings-section" />,
}))

describe('ProfileSecurityPage social account actions', () => {
  afterEach(() => {
    vi.restoreAllMocks()
  })

  beforeEach(() => {
    window.history.replaceState({}, '', '/profile/security')
    useAuthMock.mockReturnValue({
      user: { id: 1, avatar: '', username: 'admin' },
      refreshUser: vi.fn(),
    })
    getAuthCapabilitiesMock.mockResolvedValue({
      password: true,
      email_activation: false,
      email_code: false,
      sms_code: false,
      password_reset: true,
      admin_bootstrap_required: false,
      oauth_providers: [{ provider: 'github', name: 'GitHub' }],
    })
    listSocialAccountsMock.mockResolvedValue([])
    startSocialBindingMock.mockResolvedValue({
      auth_url: 'https://oauth.example.com/github',
      state: 'state-demo',
    })
    unbindSocialAccountMock.mockResolvedValue(undefined)
    getTOTPStatusMock.mockResolvedValue({ totp_enabled: false })
    listDevicesMock.mockResolvedValue({ items: [] })
    listMyLoginLogsMock.mockResolvedValue({ items: [] })
    listMyOperationLogsMock.mockResolvedValue({ items: [] })
    assignMock.mockReset()
    vi.spyOn(window, 'getComputedStyle').mockImplementation((element) => {
      return originalGetComputedStyle.call(window, element)
    })
    Object.defineProperty(window, 'location', {
      configurable: true,
      value: {
        ...window.location,
        assign: assignMock,
      },
    })
  })

  it('starts the social binding flow from the security page', async () => {
    const user = userEvent.setup()

    render(<ProfileSecurityPage />)

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

    await user.click(screen.getByRole('button', { name: '绑定 GitHub' }))
    await user.type(screen.getByPlaceholderText('有密码时建议填写'), 'SecurePass123')
    await user.click(screen.getByRole('button', { name: '继续授权' }))

    await waitFor(() =>
      expect(startSocialBindingMock).toHaveBeenCalledWith({
        provider: 'github',
        return_to: '/profile/security',
        current_password: 'SecurePass123',
        totp_code: undefined,
      }),
    )
    expect(assignMock).toHaveBeenCalledWith('https://oauth.example.com/github')
  })
})
