import { describe, it, expect } from 'vitest'
// Import from the pure modules directly — no electron import chain (L37).
import { parseProgress } from '../src/main/lib/formatters'
import { fmtBytes, fmtEta } from '../src/shared/format'

describe('fmtBytes', () => {
  it('formats bytes under 1 KB verbatim', () => {
    expect(fmtBytes(0)).toBe('0 B')
    expect(fmtBytes(512)).toBe('512 B')
    expect(fmtBytes(1023)).toBe('1023 B')
  })

  it('switches to KB at 1024', () => {
    expect(fmtBytes(1024)).toBe('1.0 KB')
    expect(fmtBytes(1536)).toBe('1.5 KB')
  })

  it('uses one decimal below 100, none above', () => {
    expect(fmtBytes(99 * 1024)).toBe('99.0 KB')
    expect(fmtBytes(100 * 1024)).toBe('100 KB')
    expect(fmtBytes(150 * 1024)).toBe('150 KB')
  })

  it('switches to MB and GB', () => {
    expect(fmtBytes(1024 * 1024)).toBe('1.0 MB')
    expect(fmtBytes(1024 * 1024 * 1024)).toBe('1.0 GB')
  })
})

describe('fmtEta', () => {
  it('returns undefined for null / undefined input', () => {
    expect(fmtEta(undefined)).toBeUndefined()
    expect(fmtEta(null as unknown as number)).toBeUndefined()
  })

  it('formats seconds to M:SS', () => {
    expect(fmtEta(0)).toBe('0:00')
    expect(fmtEta(59)).toBe('0:59')
    expect(fmtEta(60)).toBe('1:00')
    expect(fmtEta(90)).toBe('1:30')
    expect(fmtEta(3599)).toBe('59:59')
  })

  it('formats hours to H:MM:SS (L166)', () => {
    expect(fmtEta(3600)).toBe('1:00:00')
    expect(fmtEta(3661)).toBe('1:01:01')
    expect(fmtEta(7260)).toBe('2:01:00')
    expect(fmtEta(7384)).toBe('2:03:04')
  })

  it('clamps negative input to 0', () => {
    expect(fmtEta(-10)).toBe('0:00')
  })
})

describe('parseProgress', () => {
  const makeRaw = (parts: string[]): string => parts.join('|')

  it('returns null when there are fewer than 6 fields', () => {
    expect(parseProgress('')).toBeNull()
    expect(parseProgress('downloading|100|200|200')).toBeNull()
  })

  it('parses a normal progress line', () => {
    // status | downloaded | total | totalEst | speed | eta
    const raw = makeRaw(['downloading', '524288', '1048576', '1048576', '262144', '2'])
    const p = parseProgress(raw)
    expect(p).not.toBeNull()
    expect(p!.progress).toBeCloseTo(0.5)
    expect(p!.speedBytesPerSec).toBe(262144)
    expect(p!.etaSeconds).toBe(2)
    expect(p!.sizeLabel).toBe('1.0 MB')
    expect(p!.sizeUnknown).toBe(false)
  })

  it('falls back to totalEst when total is NA', () => {
    const raw = makeRaw(['downloading', '100', 'NA', '1000', '50', '18'])
    const p = parseProgress(raw)
    expect(p).not.toBeNull()
    expect(p!.sizeLabel).toBe('1000 B')
    expect(p!.sizeUnknown).toBe(false)
  })

  it('marks sizeUnknown when both total and totalEst are NA', () => {
    const raw = makeRaw(['downloading', '100', 'NA', 'NA', 'NA', 'NA'])
    const p = parseProgress(raw)
    expect(p).not.toBeNull()
    expect(p!.sizeUnknown).toBe(true)
    expect(p!.etaSeconds).toBeUndefined()
    expect(p!.speedBytesPerSec).toBeUndefined()
  })

  it('clamps progress to 1.0', () => {
    const raw = makeRaw(['downloading', '2000', '1000', '1000', '500', '0'])
    const p = parseProgress(raw)
    expect(p!.progress).toBe(1)
  })

  it('carries a raw ETA in seconds; the renderer formats it (L166)', () => {
    const raw = makeRaw(['downloading', '100', '1000', '1000', '10', '3661'])
    const p = parseProgress(raw)
    expect(p!.etaSeconds).toBe(3661)
    expect(fmtEta(p!.etaSeconds)).toBe('1:01:01')
  })
})
