/**
 * Tests for server/utils/qbittorrent.js pure utility functions.
 *
 * mapTorrentToDownload, formatBytes, formatSpeed, and formatEta are all
 * pure functions with no I/O — ideal unit test targets. These power the
 * dashboard card rendering so correctness matters for UX.
 */

import { mapTorrentToDownload, formatBytes, formatSpeed, formatEta } from '../../server/utils/qbittorrent.js';

// Minimal torrent fixture that satisfies mapTorrentToDownload's expectations
function makeTorrent(overrides = {}) {
  return {
    name: 'My.Show.S01E01.1080p.mkv',
    state: 'downloading',
    size: 1073741824,        // 1 GB
    completed: 536870912,    // 512 MB
    progress: 0.5,
    dlspeed: 1048576,        // 1 MB/s
    eta: 512,                // seconds
    num_seeds: 10,
    num_leechs: 3,
    availability: 1.0,
    hash: 'aabbccdd',
    category: 'sonarr',
    tags: '',
    content_path: '/downloads/My.Show.S01E01.1080p.mkv',
    save_path: '/downloads/',
    instanceName: 'i3omb',
    ...overrides
  };
}

describe('formatBytes', () => {
  it('formats 0 bytes', () => expect(formatBytes(0)).toBe('0 B'));
  it('formats bytes', () => expect(formatBytes(512)).toBe('512 B'));
  it('formats kilobytes', () => expect(formatBytes(1024)).toBe('1 KB'));
  it('formats megabytes', () => expect(formatBytes(1048576)).toBe('1 MB'));
  it('formats gigabytes', () => expect(formatBytes(1073741824)).toBe('1 GB'));
  it('formats fractional GB', () => expect(formatBytes(1610612736)).toBe('1.5 GB'));
});

describe('formatSpeed', () => {
  it('appends /s to byte count', () => expect(formatSpeed(1048576)).toBe('1 MB/s'));
  it('handles zero speed', () => expect(formatSpeed(0)).toBe('0 B/s'));
});

describe('formatEta', () => {
  it('returns ∞ for qBittorrent unknown sentinel (8640000)', () => {
    expect(formatEta(8640000)).toBe('∞');
  });
  it('returns ∞ for negative eta', () => expect(formatEta(-1)).toBe('∞'));
  it('formats minutes only', () => expect(formatEta(90)).toBe('1m'));
  it('formats hours and minutes', () => expect(formatEta(3661)).toBe('1h 1m'));
  it('formats days, hours and minutes', () => expect(formatEta(90061)).toBe('1d 1h 1m'));
  it('returns 0m for zero seconds', () => expect(formatEta(0)).toBe('0m'));
});

describe('mapTorrentToDownload', () => {
  it('maps a downloading torrent correctly', () => {
    const result = mapTorrentToDownload(makeTorrent());
    expect(result.status).toBe('Downloading');
    expect(result.progress).toBe('50.0');
    expect(result.size).toBe('1 GB');
    expect(result.speed).toBe('1 MB/s');
    expect(result.eta).toBe('8m');
    expect(result.seeds).toBe(10);
    expect(result.peers).toBe(3);
    expect(result.qbittorrent).toBe(true);
    expect(result.instanceName).toBe('i3omb');
  });

  it('maps state: stalledDL → Downloading', () => {
    expect(mapTorrentToDownload(makeTorrent({ state: 'stalledDL' })).status).toBe('Downloading');
  });

  it('maps state: uploading → Seeding', () => {
    expect(mapTorrentToDownload(makeTorrent({ state: 'uploading' })).status).toBe('Seeding');
  });

  it('maps state: pausedDL → Paused', () => {
    expect(mapTorrentToDownload(makeTorrent({ state: 'pausedDL' })).status).toBe('Paused');
  });

  it('maps state: stoppedUP → Stopped', () => {
    expect(mapTorrentToDownload(makeTorrent({ state: 'stoppedUP' })).status).toBe('Stopped');
  });

  it('maps state: error → Error', () => {
    expect(mapTorrentToDownload(makeTorrent({ state: 'error' })).status).toBe('Error');
  });

  it('passes through unknown state verbatim', () => {
    expect(mapTorrentToDownload(makeTorrent({ state: 'weirdState' })).status).toBe('weirdState');
  });

  it('computes 100% progress for completed torrent', () => {
    const result = mapTorrentToDownload(makeTorrent({ progress: 1.0 }));
    expect(result.progress).toBe('100.0');
  });

  it('uses content_path as savePath when present', () => {
    const result = mapTorrentToDownload(makeTorrent({ content_path: '/dl/file.mkv' }));
    expect(result.savePath).toBe('/dl/file.mkv');
  });

  it('falls back to save_path when content_path is absent', () => {
    const result = mapTorrentToDownload(makeTorrent({ content_path: null, save_path: '/dl/' }));
    expect(result.savePath).toBe('/dl/');
  });
});
