import 'package:flutter_test/flutter_test.dart';
import 'package:plezy/utils/stream_buffer_sizing.dart';

void main() {
  group('nextPowerOfTwo', () {
    test('rounds up to the next power of two', () {
      expect(nextPowerOfTwo(1), 1);
      expect(nextPowerOfTwo(2), 2);
      expect(nextPowerOfTwo(3), 4);
      expect(nextPowerOfTwo(52 * 1024 * 1024), 64 * 1024 * 1024);
      expect(nextPowerOfTwo(64 * 1024 * 1024), 64 * 1024 * 1024);
      expect(nextPowerOfTwo(64 * 1024 * 1024 + 1), 128 * 1024 * 1024);
    });
  });

  group('networkStreamRingBytes', () {
    test('sizes the iPhone 4K60 HDR10 repro file to 64MiB', () {
      // 69140 kbps total → 8.6 MB/s × 6s ≈ 52MB → pow2 64MiB; the guaranteed
      // seek-back half (32MiB) covers the measured ~24MB interleave gap.
      expect(networkStreamRingBytes(container: 'mov', bitrateKbps: 69140), 64 * 1024 * 1024);
    });

    test('returns null for well-interleaved or unknown containers', () {
      expect(networkStreamRingBytes(container: 'avi', bitrateKbps: 69140), isNull);
      expect(networkStreamRingBytes(container: null, bitrateKbps: 69140), isNull);
      expect(networkStreamRingBytes(container: '', bitrateKbps: 69140), isNull);
    });

    test('sizes high-bitrate Matroska direct play to 64MiB', () {
      expect(networkStreamRingBytes(container: 'mkv', bitrateKbps: 69140), 64 * 1024 * 1024);
      expect(networkStreamRingBytes(container: 'matroska', bitrateKbps: 69140), 64 * 1024 * 1024);
    });

    test('keeps ordinary Matroska direct play on the default stream ring', () {
      expect(networkStreamRingBytes(container: 'mkv', bitrateKbps: 39000), isNull);
      expect(networkStreamRingBytes(container: 'mkv', bitrateKbps: null), isNull);
      expect(networkStreamRingBytes(container: 'mkv', bitrateKbps: 0), isNull);
    });

    test('matches QuickTime-family containers case-insensitively', () {
      expect(networkStreamRingBytes(container: 'MOV', bitrateKbps: 69140), 64 * 1024 * 1024);
      expect(networkStreamRingBytes(container: 'mp4', bitrateKbps: 69140), 64 * 1024 * 1024);
    });

    test('matches ffmpeg demuxer alias lists from Jellyfin', () {
      expect(networkStreamRingBytes(container: 'mov,mp4,m4a,3gp,3g2,mj2', bitrateKbps: 69140), 64 * 1024 * 1024);
      expect(networkStreamRingBytes(container: 'matroska,webm', bitrateKbps: 69140), 64 * 1024 * 1024);
    });

    test('falls back to 64MiB when bitrate is unknown', () {
      expect(networkStreamRingBytes(container: 'mov', bitrateKbps: null), 64 * 1024 * 1024);
      expect(networkStreamRingBytes(container: 'mov', bitrateKbps: 0), 64 * 1024 * 1024);
    });

    test('clamps to the 16MiB floor for low bitrates', () {
      expect(networkStreamRingBytes(container: 'mp4', bitrateKbps: 1000), 16 * 1024 * 1024);
    });

    test('clamps to the 128MiB ceiling for very high bitrates', () {
      expect(networkStreamRingBytes(container: 'mov', bitrateKbps: 400000), 128 * 1024 * 1024);
    });

    test('respects a lower Android heap cap, including the unknown-bitrate path', () {
      expect(
        networkStreamRingBytes(container: 'mov', bitrateKbps: 69140, maxBytes: 32 * 1024 * 1024),
        32 * 1024 * 1024,
      );
      expect(networkStreamRingBytes(container: 'mov', bitrateKbps: null, maxBytes: 32 * 1024 * 1024), 32 * 1024 * 1024);
    });
  });

  group('androidStreamRingCapBytes', () {
    test('tiers by device heap with a conservative unknown fallback', () {
      expect(androidStreamRingCapBytes(0), 64 * 1024 * 1024);
      expect(androidStreamRingCapBytes(256), 32 * 1024 * 1024);
      expect(androidStreamRingCapBytes(512), 64 * 1024 * 1024);
      expect(androidStreamRingCapBytes(1024), 128 * 1024 * 1024);
    });
  });
}
