import '@testing-library/jest-dom'

import { render, screen } from '@testing-library/react'
import { vi } from 'vitest'

import { FileItem, TFileItemList, TFileTransfer } from './types'
import { PktFileUpload } from './FileUpload'

// Polyfill for ResizeObserver
if (!global.ResizeObserver) {
  class ResizeObserverPolyfill {
    observe() {}
    unobserve() {}
    disconnect() {}
  }

  global.ResizeObserver = ResizeObserverPolyfill as any
}

const NOOP = () => {}

const createMockFile = (name: string, type = 'text/plain'): File => new File(['content'], name, { type })

const createFileItem = (name: string, fileId?: string) => new FileItem(createMockFile(name), fileId)

const expectVisibleFilename = (filename: string) => {
  // Truncate renders a hidden measuring element with the same text.
  // We assert against the visible "first" part to avoid duplicate matches.
  expect(
    screen.getByText(
      (content, element) =>
        content === filename && element?.getAttribute('data-pkt-truncate-part') === 'first',
    ),
  ).toBeInTheDocument()
}

describe('QueueDisplay', () => {
  describe('Progress states', () => {
    it.each([
      {
        state: 'queued',
        progress: 'queued' as TFileTransfer['progress'],
        filename: 'queued-file.pdf',
        description: 'when no transfer exists',
      },
      {
        state: 'done',
        progress: 'done' as TFileTransfer['progress'],
        filename: 'completed-file.pdf',
        description: 'after successful upload',
      },
      {
        state: 'error',
        progress: 'error' as TFileTransfer['progress'],
        filename: 'failed-file.pdf',
        description: 'after failed upload',
      },
      {
        state: 'canceled',
        progress: 'canceled' as TFileTransfer['progress'],
        filename: 'canceled-file.pdf',
        description: 'when canceled',
      },
      // { state: 'in-progress', progress: 10 as FileTransfer['progress'], filename: 'in-progress-file.pdf', description: 'when canceled' },
    ])('should display file with $state state $description', ({ progress, filename, state }) => {
      const initialValue: TFileItemList = [createFileItem(filename, 'file-1')]
      const transfers = progress !== undefined ? [{ fileId: 'file-1', progress }] : []

      const { container } = render(
        <PktFileUpload
          id={'pktFileUploadId'}
          value={initialValue}
          name={'pktFileUpload'}
          uploadStrategy="custom"
          onFileUploadRequested={vi.fn()}
          transfers={transfers}
          onFilesChanged={NOOP}
        />,
      )

      // File should be displayed
      expectVisibleFilename(filename)

      // Should have proper class when not in progress
      const queueItem = container.querySelector('.pkt-fileupload__queue-display__item')
      expect(queueItem).toHaveClass('pkt-fileupload__queue-display__item--' + state)
      expect(queueItem).not.toHaveClass('pkt-fileupload__queue-display__item--in-progress')

      // Should not show progress bar or cancel button
      expect(container.querySelector('.pkt-fileupload__queue-display__item__progress')).not.toBeInTheDocument()
      expect(screen.queryByText('Avbryt')).not.toBeInTheDocument()
    })

    it('should display file with in-progress state and progress bar', () => {
      const initialValue: TFileItemList = [createFileItem('uploading-file.pdf', 'file-1')]

      const { container } = render(
        <PktFileUpload
          id={'pktFileUploadId'}
          value={initialValue}
          name={'pktFileUpload'}
          uploadStrategy="custom"
          onFileUploadRequested={vi.fn()}
          transfers={[{ fileId: 'file-1', progress: 0.45 }]}
          onFilesChanged={NOOP}
        />,
      )

      // File should be displayed
      expectVisibleFilename('uploading-file.pdf')

      // Should have the 'in-progress' class
      const queueItem = container.querySelector('.pkt-fileupload__queue-display__item')
      expect(queueItem).toHaveClass('pkt-fileupload__queue-display__item--in-progress')
      expect(queueItem).not.toHaveClass('pkt-fileupload__queue-display__item--done')

      // Should show progress bar
      expect(container.querySelector('.pkt-fileupload__queue-display__item__progress')).toBeInTheDocument()

      // Should show percentage
      expect(screen.getByText('45%')).toBeInTheDocument()

      // Should show cancel button
      expect(screen.getByText('Avbryt')).toBeInTheDocument()
    })

    it('should display multiple files with different progress states', () => {
      const initialValue: TFileItemList = [
        createFileItem('queued-file.pdf', 'file-1'),
        createFileItem('uploading-file.pdf', 'file-2'),
        createFileItem('completed-file.pdf', 'file-3'),
        createFileItem('failed-file.pdf', 'file-4'),
      ]

      const { container } = render(
        <PktFileUpload
          id={'pktFileUploadId'}
          value={initialValue}
          name={'pktFileUpload'}
          uploadStrategy="custom"
          onFileUploadRequested={vi.fn()}
          transfers={[
            { fileId: 'file-2', progress: 0.75 },
            { fileId: 'file-3', progress: 'done' },
            { fileId: 'file-4', progress: 'error' },
          ]}
          onFilesChanged={NOOP}
        />,
      )

      // All files should be displayed
      expectVisibleFilename('queued-file.pdf')
      expectVisibleFilename('uploading-file.pdf')
      expectVisibleFilename('completed-file.pdf')
      expectVisibleFilename('failed-file.pdf')

      // Should have 4 queue items
      const queueItems = container.querySelectorAll('.pkt-fileupload__queue-display__item')
      expect(queueItems).toHaveLength(4)

      // Only the uploading file should have in-progress class
      const inProgressItems = container.querySelectorAll('.pkt-fileupload__queue-display__item--in-progress')
      expect(inProgressItems).toHaveLength(1)

      // Only the uploading file should show progress bar and percentage
      expect(screen.getByText('75%')).toBeInTheDocument()
      expect(container.querySelectorAll('.pkt-fileupload__queue-display__item__progress')).toHaveLength(1)
    })

    it('should update progress percentage when transfer progresses', () => {
      const initialValue: TFileItemList = [createFileItem('uploading-file.pdf', 'file-1')]

      const { container, rerender } = render(
        <PktFileUpload
          id={'pktFileUploadId'}
          value={initialValue}
          name={'pktFileUpload'}
          uploadStrategy="custom"
          onFileUploadRequested={vi.fn()}
          transfers={[{ fileId: 'file-1', progress: 0.25 }]}
          onFilesChanged={NOOP}
        />,
      )

      // Initially at 25%
      expect(screen.getByText('25%')).toBeInTheDocument()

      // Update to 50%
      rerender(
        <PktFileUpload
          id={'pktFileUploadId'}
          value={initialValue}
          name={'pktFileUpload'}
          uploadStrategy="custom"
          onFileUploadRequested={vi.fn()}
          transfers={[{ fileId: 'file-1', progress: 0.5 }]}
          onFilesChanged={NOOP}
        />,
      )

      expect(screen.queryByText('25%')).not.toBeInTheDocument()
      expect(screen.getByText('50%')).toBeInTheDocument()

      // Update to done
      rerender(
        <PktFileUpload
          id={'pktFileUploadId'}
          value={initialValue}
          name={'pktFileUpload'}
          uploadStrategy="custom"
          onFileUploadRequested={vi.fn()}
          transfers={[{ fileId: 'file-1', progress: 'done' }]}
          onFilesChanged={NOOP}
        />,
      )

      // Progress percentage should no longer be visible
      expect(screen.queryByText('50%')).not.toBeInTheDocument()
      expect(container.querySelector('.pkt-fileupload__queue-display__item__progress')).not.toBeInTheDocument()
    })
  })
})
