import { setupWorker } from 'msw/browser'
import { afterAll, beforeAll, describe, expect, test } from 'vitest'
import { userEvent } from 'vitest/browser'
import { render } from 'vitest-browser-react'
import { tusHandlers } from '../../shared/tusHandlers.js'
import App from '../src/App'

const worker = setupWorker(...tusHandlers)
beforeAll(async () => {
  await worker.start({ onUnhandledRequest: 'bypass' })
})
afterAll(() => {
  worker.stop()
})

const createMockFile = (name: string, type: string, size: number = 1024) => {
  return new File(['test content'], name, { type })
}

describe('App', () => {
  test('renders all main sections and upload button is initially disabled', async () => {
    const screen = await render(<App />)

    await expect.element(screen.getByText('With list')).toBeInTheDocument()
    await expect.element(screen.getByText('With grid')).toBeInTheDocument()
    await expect
      .element(screen.getByText('With custom dropzone'))
      .toBeInTheDocument()

    const uploadButton = screen.getByRole('button', { name: /upload/i })
    await expect.element(uploadButton).toBeInTheDocument()
    await expect.element(uploadButton).toBeDisabled()
  })

  test('can add and remove files and upload', async () => {
    const screen = await render(<App />)

    const fileInput = document.getElementById(
      'uppy-dropzone-file-input-uppy',
    ) as Element
    await userEvent.upload(fileInput, createMockFile('test.txt', 'text/plain'))

    // for list and grid
    for (const element of screen.getByText('test.txt').elements()) {
      await expect.element(element).toBeInTheDocument()
    }
    await screen.getByText('remove').first().click()
    for (const element of screen.getByText('test.txt').elements()) {
      await expect.element(element).not.toBeInTheDocument()
    }

    await userEvent.upload(fileInput, createMockFile('test.txt', 'text/plain'))
    await screen.getByRole('button', { name: /upload/i }).click()
    await expect
      .element(screen.getByRole('button', { name: /complete/i }))
      .toBeInTheDocument()
  })
})

describe('ScreenCapture Component', () => {
  test('renders with title, control buttons, and close functionality works', async () => {
    const screen = await render(<App />)

    await screen.getByRole('button', { name: 'Screen Capture' }).click()

    await expect
      .element(screen.getByRole('heading', { name: 'Screen Capture' }))
      .toBeInTheDocument()

    await expect
      .element(screen.getByRole('button', { name: 'Screenshot' }))
      .toBeInTheDocument()
    await expect
      .element(screen.getByRole('button', { name: 'Record' }))
      .toBeInTheDocument()
    await expect
      .element(screen.getByRole('button', { name: 'Stop' }))
      .toBeInTheDocument()
    await expect
      .element(screen.getByRole('button', { name: 'Submit' }))
      .toBeInTheDocument()
    await expect
      .element(screen.getByRole('button', { name: 'Discard' }))
      .toBeInTheDocument()

    const closeButton = screen.getByText('✕')
    await closeButton.click()
  })
})

describe('Webcam Component', () => {
  test('renders with title, control buttons, and close functionality works', async () => {
    const screen = await render(<App />)

    await screen.getByRole('button', { name: 'Webcam' }).click()

    await expect
      .element(screen.getByRole('heading', { name: 'Camera' }))
      .toBeInTheDocument()

    await expect
      .element(screen.getByRole('button', { name: 'Snapshot' }))
      .toBeInTheDocument()
    await expect
      .element(screen.getByRole('button', { name: 'Record' }))
      .toBeInTheDocument()
    await expect
      .element(screen.getByRole('button', { name: 'Stop' }))
      .toBeInTheDocument()
    await expect
      .element(screen.getByRole('button', { name: 'Submit' }))
      .toBeInTheDocument()
    await expect
      .element(screen.getByRole('button', { name: 'Discard' }))
      .toBeInTheDocument()

    const closeButton = screen.getByText('✕')
    await closeButton.click()
  })
})

describe('RemoteSource Component', () => {
  test('renders login button and login interaction works', async () => {
    const screen = await render(<App />)

    await screen.getByRole('button', { name: 'Dropbox' }).click()

    const loginButton = screen.getByRole('button', { name: 'Login' })
    await expect.element(loginButton).toBeInTheDocument()

    await loginButton.click()
  })
})
