// Copyright 2014 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

@TestOn('!chrome')

import 'dart:async';
import 'dart:io';
import 'dart:typed_data';

import 'package:flutter/foundation.dart';
import 'package:flutter_test/flutter_test.dart';

final Uint8List chunkOne = Uint8List.fromList(<int>[0, 1, 2, 3, 4, 5]);
final Uint8List chunkTwo = Uint8List.fromList(<int>[6, 7, 8, 9, 10]);

void main() {
  group(consolidateHttpClientResponseBytes, () {
    late MockHttpClientResponse response;

    setUp(() {
      response = MockHttpClientResponse(
        chunkOne: chunkOne,
        chunkTwo: chunkTwo,
      );
    });

    test('Converts an HttpClientResponse with contentLength to bytes', () async {
      response.contentLength = chunkOne.length + chunkTwo.length;
      final List<int> bytes =
          await consolidateHttpClientResponseBytes(response);

      expect(bytes, <int>[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]);
    });

    test('Converts a compressed HttpClientResponse with contentLength to bytes', () async {
      response.contentLength = chunkOne.length;
      final List<int> bytes =
          await consolidateHttpClientResponseBytes(response);

      expect(bytes, <int>[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]);
    });

    test('Converts an HttpClientResponse without contentLength to bytes', () async {
      response.contentLength = -1;
      final List<int> bytes =
          await consolidateHttpClientResponseBytes(response);

      expect(bytes, <int>[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]);
    });

    test('Notifies onBytesReceived for every chunk of bytes', () async {
      final int syntheticTotal = (chunkOne.length + chunkTwo.length) * 2;
      response.contentLength = syntheticTotal;
      final List<int?> records = <int?>[];
      await consolidateHttpClientResponseBytes(
        response,
        onBytesReceived: (int cumulative, int? total) {
          records.addAll(<int?>[cumulative, total]);
        },
      );

      expect(records, <int>[
        chunkOne.length,
        syntheticTotal,
        chunkOne.length + chunkTwo.length,
        syntheticTotal,
      ]);
    });

    test('forwards errors from HttpClientResponse', () async {
      response = MockHttpClientResponse(error: Exception('Test Error'));
      response.contentLength = -1;

      expect(consolidateHttpClientResponseBytes(response), throwsException);
    });

    test('Propagates error to Future return value if onBytesReceived throws', () async {
      response.contentLength = -1;
      final Future<List<int>> result = consolidateHttpClientResponseBytes(
        response,
        onBytesReceived: (int cumulative, int? total) {
          throw 'misbehaving callback';
        },
      );

      expect(result, throwsA(equals('misbehaving callback')));
    });

    group('when gzipped', () {
      final List<int> gzipped = gzip.encode(chunkOne.followedBy(chunkTwo).toList());
      final List<int> gzippedChunkOne = gzipped.sublist(0, gzipped.length ~/ 2);
      final List<int> gzippedChunkTwo = gzipped.sublist(gzipped.length ~/ 2);

      setUp(() {
        response = MockHttpClientResponse(chunkOne: gzippedChunkOne, chunkTwo: gzippedChunkTwo);
        response.compressionState = HttpClientResponseCompressionState.compressed;
      });

      test('Uncompresses GZIP bytes if autoUncompress is true and response.compressionState is compressed', () async {
        response.contentLength = gzipped.length;
        final List<int> bytes = await consolidateHttpClientResponseBytes(response);
        expect(bytes, <int>[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]);
      });

      test('returns gzipped bytes if autoUncompress is false and response.compressionState is compressed', () async {
        response.contentLength = gzipped.length;
        final List<int> bytes = await consolidateHttpClientResponseBytes(response, autoUncompress: false);
        expect(bytes, gzipped);
      });

      test('Notifies onBytesReceived with gzipped numbers', () async {
        response.contentLength = gzipped.length;
        final List<int?> records = <int?>[];
        await consolidateHttpClientResponseBytes(
          response,
          onBytesReceived: (int cumulative, int? total) {
            records.addAll(<int?>[cumulative, total]);
          },
        );

        expect(records, <int>[
          gzippedChunkOne.length,
          gzipped.length,
          gzipped.length,
          gzipped.length,
        ]);
      });

      test('Notifies onBytesReceived with expectedContentLength of -1 if response.compressionState is decompressed', () async {
        final int syntheticTotal = (chunkOne.length + chunkTwo.length) * 2;
        response.compressionState = HttpClientResponseCompressionState.decompressed;
        response.contentLength = syntheticTotal;
        final List<int?> records = <int?>[];
        await consolidateHttpClientResponseBytes(
          response,
          onBytesReceived: (int cumulative, int? total) {
            records.addAll(<int?>[cumulative, total]);
          },
        );

        expect(records, <int?>[
          gzippedChunkOne.length,
          null,
          gzipped.length,
          null,
        ]);
      });
    });
  });
}

class MockHttpClientResponse extends Fake implements HttpClientResponse {
  MockHttpClientResponse({this.error, this.chunkOne = const <int>[], this.chunkTwo = const <int>[]});

  final dynamic error;
  final List<int> chunkOne;
  final List<int> chunkTwo;

  @override
  int contentLength = 0;

  @override
  HttpClientResponseCompressionState compressionState = HttpClientResponseCompressionState.notCompressed;

  @override
  StreamSubscription<List<int>> listen(void Function(List<int> event)? onData, {Function? onError, void Function()? onDone, bool? cancelOnError}) {
    if (error != null) {
      return Stream<List<int>>.fromFuture(Future<List<int>>.error(error as Object)).listen(
          onData,
          onDone: onDone,
          onError: onError,
          cancelOnError: cancelOnError,
        );
    }
    return Stream<List<int>>.fromIterable(<List<int>>[chunkOne, chunkTwo]).listen(
      onData,
      onDone: onDone,
      onError: onError,
      cancelOnError: cancelOnError,
    );
  }
}
