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

describe('ArtworkAwards medal confirmations', () => {
  beforeEach(() => {
    vi.stubGlobal('fetch', vi.fn())
  })

  afterEach(() => {
    cleanup()
    vi.unstubAllGlobals()
    vi.clearAllMocks()
  })

  it('asks for confirmation before removing the active medal', async () => {
    const user = userEvent.setup()
    const fetchMock = vi.mocked(fetch)

    fetchMock.mockResolvedValue({
      ok: true,
      json: async () => ({
        medals: { gold: 0, silver: 0, bronze: 0, score: 0 },
        current_user_medal: null,
      }),
    })

    render(
      <ArtworkAwards
        artwork={{ id: 69461, viewer: { id: 2 }, user: { id: 7 } }}
        isAuthenticated
        initialAwards={{ gold: 1, silver: 0, bronze: 0, score: 5, current_user_medal: 'gold' }}
      />,
    )

    await user.click(screen.getByRole('button', { name: /gold/i }))

    expect(screen.getByRole('dialog', { name: /remove gold medal\?/i })).not.toBeNull()
    expect(fetchMock).not.toHaveBeenCalled()

    await user.click(screen.getByRole('button', { name: /remove medal/i }))

    await waitFor(() => {
      expect(fetchMock).toHaveBeenCalledTimes(1)
    })

    expect(fetchMock).toHaveBeenCalledWith(
      '/api/artworks/69461/medal',
      expect.objectContaining({
        method: 'DELETE',
      }),
    )
  })

  it('asks for confirmation before changing an existing medal', async () => {
    const user = userEvent.setup()
    const fetchMock = vi.mocked(fetch)

    fetchMock.mockResolvedValue({
      ok: true,
      json: async () => ({
        medals: { gold: 0, silver: 1, bronze: 0, score: 3 },
        current_user_medal: 'silver',
      }),
    })

    render(
      <ArtworkAwards
        artwork={{ id: 69461, viewer: { id: 2 }, user: { id: 7 } }}
        isAuthenticated
        initialAwards={{ gold: 1, silver: 0, bronze: 0, score: 5, current_user_medal: 'gold' }}
      />,
    )

    await user.click(screen.getByRole('button', { name: /silver/i }))

    expect(screen.getByRole('dialog', { name: /change medal to silver\?/i })).not.toBeNull()
    expect(fetchMock).not.toHaveBeenCalled()

    await user.click(screen.getByRole('button', { name: /change to silver/i }))

    await waitFor(() => {
      expect(fetchMock).toHaveBeenCalledTimes(1)
    })

    expect(fetchMock).toHaveBeenCalledWith(
      '/api/artworks/69461/medal',
      expect.objectContaining({
        method: 'POST',
        body: JSON.stringify({ medal_type: 'silver' }),
      }),
    )
  })

  it('still awards a new medal immediately when the viewer has not voted yet', async () => {
    const user = userEvent.setup()
    const fetchMock = vi.mocked(fetch)

    fetchMock.mockResolvedValue({
      ok: true,
      json: async () => ({
        medals: { gold: 0, silver: 1, bronze: 0, score: 3 },
        current_user_medal: 'silver',
      }),
    })

    render(
      <ArtworkAwards
        artwork={{ id: 69461, viewer: { id: 2 }, user: { id: 7 } }}
        isAuthenticated
        initialAwards={{ gold: 0, silver: 0, bronze: 0, score: 0, current_user_medal: null }}
      />,
    )

    await user.click(screen.getByRole('button', { name: /silver/i }))

    await waitFor(() => {
      expect(fetchMock).toHaveBeenCalledTimes(1)
    })

    expect(screen.queryByRole('dialog')).toBeNull()
  })
})