import { describe, it, expect } from 'vitest'
import type { PlaylistEntry } from '../src/shared/ipc'
import { buildPlaylistAddEntries } from '../src/renderer/src/components/downloadBar/playlistEntries'
import type { ChosenFormat } from '../src/renderer/src/store/downloadTypes'
import type { MediaKind } from '../src/renderer/src/store/downloads'

function entry(index: number, over: Partial<PlaylistEntry> = {}): PlaylistEntry {
  return {
    index,
    id: `v${index}`,
    title: `Item ${index}`,
    url: `https://youtube.com/watch?v=v${index}`,
    durationLabel: '10:00',
    uploader: 'Chan',
    ...over
  }
}

/** Build the ctx the way useDownloadBar does, from per-entry override maps. */
function ctx(opts: {
  barKind?: MediaKind
  barQuality?: string
  kinds?: Record<number, MediaKind>
  formats?: Record<number, ChosenFormat>
}) {
  const { barKind = 'video', barQuality = '1080p', kinds = {}, formats = {} } = opts
  return {
    barKind,
    barQuality,
    effKind: (i: number): MediaKind => kinds[i] ?? barKind,
    itemFormats: formats
  }
}

describe('buildPlaylistAddEntries', () => {
  it('uses the bar preset when an entry matches the bar kind and has no override', () => {
    const [row] = buildPlaylistAddEntries([entry(1)], ctx({ barKind: 'video', barQuality: '720p' }))
    expect(row.kind).toBe('video')
    expect(row.quality).toBe('720p')
    expect(row.opts?.format).toBeUndefined()
    // metadata is forwarded so the queue row shows a title before probing
    expect(row.opts?.title).toBe('Item 1')
    expect(row.opts?.channel).toBe('Chan')
  })

  it('falls back to that kind default when an entry override differs from the bar kind', () => {
    const [row] = buildPlaylistAddEntries(
      [entry(1)],
      ctx({ barKind: 'video', barQuality: '720p', kinds: { 1: 'audio' } })
    )
    expect(row.kind).toBe('audio')
    // audio's first quality option, not the bar's video '720p'
    expect(row.quality).toBe('Best')
    expect(row.opts?.format).toBeUndefined()
  })

  it('carries an exact per-item format on a video row', () => {
    const fmt: ChosenFormat = { id: '299', hasAudio: false, label: '1080p60 · mp4' }
    const [row] = buildPlaylistAddEntries([entry(1)], ctx({ formats: { 1: fmt } }))
    expect(row.kind).toBe('video')
    expect(row.opts?.format).toEqual(fmt)
    // the chosen format's label doubles as the queue-row quality text
    expect(row.quality).toBe('1080p60 · mp4')
  })

  it('ignores a stored format on a row that is set to audio', () => {
    const fmt: ChosenFormat = { id: '299', hasAudio: false, label: '1080p60 · mp4' }
    const [row] = buildPlaylistAddEntries(
      [entry(1)],
      ctx({ kinds: { 1: 'audio' }, formats: { 1: fmt } })
    )
    expect(row.kind).toBe('audio')
    expect(row.opts?.format).toBeUndefined()
    expect(row.quality).toBe('Best')
  })

  it('maps a mixed batch independently per entry', () => {
    const fmt: ChosenFormat = { id: '136', hasAudio: false, label: '720p · mp4' }
    const rows = buildPlaylistAddEntries(
      [entry(1), entry(2), entry(3)],
      ctx({
        barKind: 'video',
        barQuality: '1080p',
        kinds: { 2: 'audio' },
        formats: { 3: fmt }
      })
    )
    expect(rows.map((r) => r.kind)).toEqual(['video', 'audio', 'video'])
    expect(rows[0].opts?.format).toBeUndefined()
    expect(rows[0].quality).toBe('1080p')
    expect(rows[1].quality).toBe('Best')
    expect(rows[2].opts?.format).toEqual(fmt)
    expect(rows[2].quality).toBe('720p · mp4')
  })
})
