import { fireEvent, render, screen, waitFor } from '@testing-library/react'
import { createMemoryHistory } from 'history'
import { Router } from 'react-router-dom'

import { registration } from 'dbaas/services/account'

import SignUp from './index'

jest.mock('@tidbcloud/uikit', () => ({
  Box: ({ children }: React.PropsWithChildren) => <div>{children}</div>,
  Card: ({ children }: React.PropsWithChildren) => <div>{children}</div>,
  Flex: ({ children }: React.PropsWithChildren) => <div>{children}</div>,
  Form: ({ onSubmit }: { onSubmit: (data: Record<string, unknown>) => void }) => (
    <button
      onClick={() =>
        onSubmit({
          email: 'person@example.com',
          password: 'Password1',
          company: 'Example',
          country: 'US',
          accept_service: true
        })
      }
    >
      Submit
    </button>
  ),
  Typography: ({ children }: React.PropsWithChildren) => <div>{children}</div>
}))

jest.mock('dbaas/screens/User/Common/AcceptServices', () => ({
  AcceptServices: () => null
}))

jest.mock('dbaas/screens/User/Common/FormFields', () => ({
  EmailField: () => null,
  NameFields: () => null,
  PasswordField: () => null
}))

jest.mock('dbaas/services/account', () => ({
  registration: jest.fn()
}))

jest.mock('dbaas/utils/tracking', () => ({
  eventTracking: jest.fn(),
  getUTMSource: () => ({}),
  REGISTER_TYPES: { SIGNUP: 'SIGNUP' },
  reportGA: jest.fn()
}))

jest.mock('dbaas/utils/tracking/usePageViewTracking', () => ({
  useGAPageView: jest.fn()
}))

jest.mock('../Components/helpers', () => ({
  useIsMdScreen: () => false
}))

jest.mock('../Components/Shell', () => ({
  PageShell: ({ children }: React.PropsWithChildren) => <div>{children}</div>
}))

jest.mock('../Components/SSO', () => ({
  SSOLogin: () => null
}))

const registrationMock = registration as jest.MockedFunction<typeof registration>

const renderSignUp = (search: string) => {
  const history = createMemoryHistory({ initialEntries: [`/oauth/signup${search}`] })
  window.history.pushState({}, '', `/oauth/signup${search}`)

  render(
    <Router history={history}>
      <SignUp />
    </Router>
  )

  return history
}

describe('OAuth signup return target', () => {
  beforeEach(() => {
    registrationMock.mockReset()
    registrationMock.mockResolvedValue(undefined as never)
  })

  test('does not submit or propagate an executable return target', async () => {
    const history = renderSignUp('?returnTo=javascript%3Aalert(document.cookie)')

    fireEvent.click(screen.getByRole('button', { name: 'Submit' }))

    await waitFor(() => expect(registrationMock).toHaveBeenCalled())

    expect(registrationMock.mock.calls[0][0].return_url).toBeUndefined()
    expect(history.location.search).not.toContain('returnTo=')
  })

  test('normalizes and propagates a same-origin return target', async () => {
    const history = renderSignUp('?returnTo=http%3A%2F%2Flocalhost%2Foauth%2Fauthorize%3Fclient_id%3Dtest')

    fireEvent.click(screen.getByRole('button', { name: 'Submit' }))

    await waitFor(() => expect(registrationMock).toHaveBeenCalled())

    expect(registrationMock.mock.calls[0][0].return_url).toBe(
      encodeURIComponent('/oauth/signin?returnTo=' + encodeURIComponent('/oauth/authorize?client_id=test'))
    )
    expect(new URLSearchParams(history.location.search).get('returnTo')).toBe('/oauth/authorize?client_id=test')
  })
})
