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

import PostImportThumbnailPreview from '@/components/posts/import/PostImportThumbnailPreview'

const api = vi.hoisted (() => ({
  apiGet: vi.fn (),
}))

vi.mock ('@/lib/api', () => api)

describe ('PostImportThumbnailPreview', () => {
  beforeEach (() => {
    vi.clearAllMocks ()
    globalThis.URL.createObjectURL = vi.fn (() => 'blob:preview')
    globalThis.URL.revokeObjectURL = vi.fn ()
  })

  it ('uses a backend-fetched blob URL instead of the external thumbnail URL directly', async () => {
    api.apiGet.mockResolvedValueOnce (new Blob (['img'], { type: 'image/png' }))

    render (
        <PostImportThumbnailPreview
            url="https://example.com/thumbnail.jpg"
            className="h-10 w-10"/>)

    await waitFor (() => {
      expect (screen.getByRole ('img')).toHaveAttribute ('src', 'blob:preview')
    })
    expect (screen.getByRole ('img')).not.toHaveAttribute (
        'src',
        'https://example.com/thumbnail.jpg')
    expect (api.apiGet).toHaveBeenCalledWith ('/preview/thumbnail', {
      params: { url: 'https://example.com/thumbnail.jpg' },
      responseType: 'blob' })
  })

  it ('does not render the unsafe URL directly when preview fetching fails', async () => {
    api.apiGet.mockRejectedValueOnce (new Error ('unsafe'))

    const { container } = render (
        <PostImportThumbnailPreview
            url="http://127.0.0.1/private.png"
            className="h-10 w-10"/>)

    await waitFor (() => {
      expect (screen.queryByRole ('img')).toBeNull ()
    })
    expect (screen.queryByText ('サムネールを表示できません')).toBeNull ()
    expect (screen.queryByText ('なし')).toBeNull ()
    expect (container.querySelector ('div.rounded.border.bg-muted')).not.toBeNull ()
    expect (container.textContent).toBe ('')
    expect (screen.queryByRole ('img')).toBeNull ()
  })

  it ('revokes the old object URL when the source URL changes', async () => {
    const createObjectUrlMock =
        globalThis.URL.createObjectURL as unknown as ReturnType<typeof vi.fn>
    createObjectUrlMock
        .mockReturnValueOnce ('blob:first')
        .mockReturnValueOnce ('blob:second')
    api.apiGet
        .mockResolvedValueOnce (new Blob (['first'], { type: 'image/png' }))
        .mockResolvedValueOnce (new Blob (['second'], { type: 'image/png' }))

    const { rerender } = render (
        <PostImportThumbnailPreview
            url="https://example.com/first.jpg"
            className="h-10 w-10"/>)
    await waitFor (() => {
      expect (screen.getByRole ('img')).toHaveAttribute ('src', 'blob:first')
    })

    rerender (
        <PostImportThumbnailPreview
            url="https://example.com/second.jpg"
            className="h-10 w-10"/>)

    await waitFor (() => {
      expect (screen.getByRole ('img')).toHaveAttribute ('src', 'blob:second')
    })
    expect (globalThis.URL.revokeObjectURL).toHaveBeenCalledWith ('blob:first')
  })
})
