// Copyright 2013 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.

/// Utilities for loading images from the network.
///
/// This library expands the capabilities of the basic [Image.network] and
/// [NetworkImage] provided by Flutter core libraries, to include a retry
/// mechanism and connectivity detection.
library network;

import 'dart:async';
import 'dart:io' as io;
import 'dart:math' as math;
// TODO(a14n): remove this import once Flutter 3.1 or later reaches stable (including flutter/flutter#104231)
// ignore: unnecessary_import
import 'dart:typed_data';
import 'dart:ui' as ui;

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

/// Fetches the image from the given URL, associating it with the given scale.
///
/// If [fetchStrategy] is specified, uses it instead of the
/// [defaultFetchStrategy] to obtain instructions for fetching the URL.
///
/// The image will be cached regardless of cache headers from the server.
@immutable
class NetworkImageWithRetry extends ImageProvider<NetworkImageWithRetry> {
  /// Creates an object that fetches the image at the given [url].
  const NetworkImageWithRetry(
    this.url, {
    this.scale = 1.0,
    this.fetchStrategy = defaultFetchStrategy,
    this.headers,
  });

  /// The HTTP client used to download images.
  static final io.HttpClient _client = io.HttpClient();

  /// The URL from which the image will be fetched.
  final String url;

  /// The scale to place in the [ImageInfo] object of the image.
  final double scale;

  /// The strategy used to fetch the [url] and retry when the fetch fails.
  ///
  /// This function is called at least once and may be called multiple times.
  /// The first time it is called, it is passed a null [FetchFailure], which
  /// indicates that this is the first attempt to fetch the [url]. Subsequent
  /// calls pass non-null [FetchFailure] values, which indicate that previous
  /// fetch attempts failed.
  final FetchStrategy fetchStrategy;

  /// HTTP Headers applied to the request.
  ///
  /// Keys from this map will be used as header field names and the
  /// values will be used as header values. A list of header names can
  /// be found at https://datatracker.ietf.org/doc/html/rfc7231#section-8.3
  ///
  /// If the value is a DateTime, an HTTP date format will be applied.
  /// If the value is an Iterable, each element will be added separately.
  /// For all other types the default Object.toString method will be used.
  ///
  /// Header names are converted to lower-case. If two header names are
  /// the same when converted to lower-case, they are considered to be
  /// the same header, with one set of values.
  ///
  /// For example, to add an authorization header to the request:
  ///
  /// final NetworkImageWithRetry subject = NetworkImageWithRetry(
  ///   Uri.parse('https://www.flutter.com/top_secret.png'),
  ///   headers: <String, Object>{
  ///     'Authorization': base64Encode(utf8.encode('user:password'))
  ///   },
  /// );
  final Map<String, Object>? headers;

  /// Used by [defaultFetchStrategy].
  ///
  /// This indirection is necessary because [defaultFetchStrategy] is used as
  /// the default constructor argument value, which requires that it be a const
  /// expression.
  static final FetchStrategy _defaultFetchStrategyFunction =
      const FetchStrategyBuilder().build();

  /// The [FetchStrategy] that [NetworkImageWithRetry] uses by default.
  static Future<FetchInstructions> defaultFetchStrategy(
      Uri uri, FetchFailure? failure) {
    return _defaultFetchStrategyFunction(uri, failure);
  }

  @override
  Future<NetworkImageWithRetry> obtainKey(ImageConfiguration configuration) {
    return SynchronousFuture<NetworkImageWithRetry>(this);
  }

  @override
  // TODO(cyanglaz): migrate to use the new APIs
  // https://github.com/flutter/flutter/issues/105336
  // ignore: deprecated_member_use
  ImageStreamCompleter load(NetworkImageWithRetry key, DecoderCallback decode) {
    return OneFrameImageStreamCompleter(_loadWithRetry(key, decode),
        informationCollector: () sync* {
      yield ErrorDescription('Image provider: $this');
      yield ErrorDescription('Image key: $key');
    });
  }

  void _debugCheckInstructions(FetchInstructions? instructions) {
    assert(() {
      if (instructions == null) {
        if (fetchStrategy == defaultFetchStrategy) {
          throw StateError(
              'The default FetchStrategy returned null FetchInstructions. This\n'
              'is likely a bug in $runtimeType. Please file a bug at\n'
              'https://github.com/flutter/flutter/issues.');
        } else {
          throw StateError(
              'The custom FetchStrategy used to fetch $url returned null\n'
              'FetchInstructions. FetchInstructions must never be null, but\n'
              'instead instruct to either make another fetch attempt or give up.');
        }
      }
      return true;
    }());
  }

  Future<ImageInfo> _loadWithRetry(
      // TODO(cyanglaz): migrate to use the new APIs
      // https://github.com/flutter/flutter/issues/105336
      // ignore: deprecated_member_use
      NetworkImageWithRetry key,
      // ignore: deprecated_member_use
      DecoderCallback decode) async {
    assert(key == this);

    final Stopwatch stopwatch = Stopwatch()..start();
    final Uri resolved = Uri.base.resolve(key.url);
    FetchInstructions instructions = await fetchStrategy(resolved, null);
    _debugCheckInstructions(instructions);
    int attemptCount = 0;
    FetchFailure? lastFailure;

    while (!instructions.shouldGiveUp) {
      attemptCount += 1;
      io.HttpClientRequest? request;
      try {
        request = await _client
            .getUrl(instructions.uri)
            .timeout(instructions.timeout);

        headers?.forEach((String key, Object value) {
          request?.headers.add(key, value);
        });

        final io.HttpClientResponse response =
            await request.close().timeout(instructions.timeout);

        if (response.statusCode != 200) {
          throw FetchFailure._(
            totalDuration: stopwatch.elapsed,
            attemptCount: attemptCount,
            httpStatusCode: response.statusCode,
          );
        }

        final _Uint8ListBuilder builder = await response
            .fold(
              _Uint8ListBuilder(),
              (_Uint8ListBuilder buffer, List<int> bytes) => buffer..add(bytes),
            )
            .timeout(instructions.timeout);

        final Uint8List bytes = builder.data;

        if (bytes.lengthInBytes == 0) {
          throw FetchFailure._(
            totalDuration: stopwatch.elapsed,
            attemptCount: attemptCount,
            httpStatusCode: response.statusCode,
          );
        }

        final ui.Codec codec = await decode(bytes);
        final ui.Image image = (await codec.getNextFrame()).image;
        return ImageInfo(
          image: image,
          scale: key.scale,
        );
      } catch (error) {
        request?.close();
        lastFailure = error is FetchFailure
            ? error
            : FetchFailure._(
                totalDuration: stopwatch.elapsed,
                attemptCount: attemptCount,
                originalException: error,
              );
        instructions = await fetchStrategy(instructions.uri, lastFailure);
        _debugCheckInstructions(instructions);
      }
    }

    if (instructions.alternativeImage != null) {
      return instructions.alternativeImage!;
    }

    assert(lastFailure != null);

    if (FlutterError.onError != null) {
      FlutterError.onError!(FlutterErrorDetails(
        exception: lastFailure!,
        library: 'package:flutter_image',
        context:
            ErrorDescription('$runtimeType failed to load ${instructions.uri}'),
      ));
    }

    throw lastFailure!;
  }

  @override
  bool operator ==(dynamic other) {
    if (other.runtimeType != runtimeType) {
      return false;
    }
    return other is NetworkImageWithRetry &&
        url == other.url &&
        scale == other.scale;
  }

  @override
  int get hashCode => Object.hash(url, scale);

  @override
  String toString() => '$runtimeType("$url", scale: $scale)';
}

/// This function is called to get [FetchInstructions] to fetch an image.
///
/// The instructions are executed as soon as possible after the returned
/// [Future] resolves. If a delay in necessary between retries, use a delayed
/// [Future], such as [Future.delayed]. This is useful for implementing
/// back-off strategies and for recovering from lack of connectivity.
///
/// [uri] is the last requested image URI. A [FetchStrategy] may choose to use
/// a different URI (see [FetchInstructions.uri]).
///
/// If [failure] is `null`, then this is the first attempt to fetch the image.
///
/// If the [failure] is not `null`, it contains the information about the
/// previous attempt to fetch the image. A [FetchStrategy] may attempt to
/// recover from the failure by returning [FetchInstructions] that instruct
/// [NetworkImageWithRetry] to try again.
///
/// See [NetworkImageWithRetry.defaultFetchStrategy] for an example.
typedef FetchStrategy = Future<FetchInstructions> Function(
    Uri uri, FetchFailure? failure);

/// Instructions [NetworkImageWithRetry] uses to fetch the image.
@immutable
class FetchInstructions {
  /// Instructs [NetworkImageWithRetry] to give up trying to download the image.
  const FetchInstructions.giveUp({
    required this.uri,
    this.alternativeImage,
  })  : shouldGiveUp = true,
        timeout = Duration.zero;

  /// Instructs [NetworkImageWithRetry] to attempt to download the image from
  /// the given [uri] and [timeout] if it takes too long.
  const FetchInstructions.attempt({
    required this.uri,
    required this.timeout,
  })  : shouldGiveUp = false,
        alternativeImage = null;

  /// Instructs to give up trying.
  ///
  /// If [alternativeImage] is `null` reports the latest [FetchFailure] to
  /// [FlutterError].
  final bool shouldGiveUp;

  /// Timeout for the next network call.
  final Duration timeout;

  /// The URI to use on the next attempt.
  final Uri uri;

  /// Instructs to give up and use this image instead.
  final Future<ImageInfo>? alternativeImage;

  @override
  String toString() {
    return '$runtimeType(\n'
        '  shouldGiveUp: $shouldGiveUp\n'
        '  timeout: $timeout\n'
        '  uri: $uri\n'
        '  alternativeImage?: ${alternativeImage != null ? 'yes' : 'no'}\n'
        ')';
  }
}

/// Contains information about a failed attempt to fetch an image.
@immutable
class FetchFailure implements Exception {
  const FetchFailure._({
    required this.totalDuration,
    required this.attemptCount,
    this.httpStatusCode,
    this.originalException,
  }) : assert(attemptCount > 0);

  /// The total amount of time it has taken so far to download the image.
  final Duration totalDuration;

  /// The number of times [NetworkImageWithRetry] attempted to fetch the image
  /// so far.
  ///
  /// This value starts with 1 and grows by 1 with each attempt to fetch the
  /// image.
  final int attemptCount;

  /// HTTP status code, such as 500.
  final int? httpStatusCode;

  /// The exception that caused the fetch failure.
  final dynamic originalException;

  @override
  String toString() {
    return '$runtimeType(\n'
        '  attemptCount: $attemptCount\n'
        '  httpStatusCode: $httpStatusCode\n'
        '  totalDuration: $totalDuration\n'
        '  originalException: $originalException\n'
        ')';
  }
}

/// An indefinitely growing builder of a [Uint8List].
class _Uint8ListBuilder {
  static const int _kInitialSize = 100000; // 100KB-ish

  int _usedLength = 0;
  Uint8List _buffer = Uint8List(_kInitialSize);

  Uint8List get data => Uint8List.view(_buffer.buffer, 0, _usedLength);

  void add(List<int> bytes) {
    _ensureCanAdd(bytes.length);
    _buffer.setAll(_usedLength, bytes);
    _usedLength += bytes.length;
  }

  void _ensureCanAdd(int byteCount) {
    final int totalSpaceNeeded = _usedLength + byteCount;

    int newLength = _buffer.length;
    while (totalSpaceNeeded > newLength) {
      newLength *= 2;
    }

    if (newLength != _buffer.length) {
      final Uint8List newBuffer = Uint8List(newLength);
      newBuffer.setAll(0, _buffer);
      newBuffer.setRange(0, _usedLength, _buffer);
      _buffer = newBuffer;
    }
  }
}

/// Determines whether the given HTTP [statusCode] is transient.
typedef TransientHttpStatusCodePredicate = bool Function(int statusCode);

/// Builds a [FetchStrategy] function that retries up to a certain amount of
/// times for up to a certain amount of time.
///
/// Pauses between retries with pauses growing exponentially (known as
/// exponential backoff). Each attempt is subject to a [timeout]. Retries only
/// those HTTP status codes considered transient by a
/// [transientHttpStatusCodePredicate] function.
class FetchStrategyBuilder {
  /// Creates a fetch strategy builder.
  ///
  /// All parameters must be non-null.
  const FetchStrategyBuilder({
    this.timeout = const Duration(seconds: 30),
    this.totalFetchTimeout = const Duration(minutes: 1),
    this.maxAttempts = 5,
    this.initialPauseBetweenRetries = const Duration(seconds: 1),
    this.exponentialBackoffMultiplier = 2,
    this.transientHttpStatusCodePredicate =
        defaultTransientHttpStatusCodePredicate,
  });

  /// A list of HTTP status codes that can generally be retried.
  ///
  /// You may want to use a different list depending on the needs of your
  /// application.
  static const List<int> defaultTransientHttpStatusCodes = <int>[
    0, // Network error
    408, // Request timeout
    500, // Internal server error
    502, // Bad gateway
    503, // Service unavailable
    504 // Gateway timeout
  ];

  /// Maximum amount of time a single fetch attempt is allowed to take.
  final Duration timeout;

  /// A strategy built by this builder will retry for up to this amount of time
  /// before giving up.
  final Duration totalFetchTimeout;

  /// Maximum number of attempts a strategy will make before giving up.
  final int maxAttempts;

  /// Initial amount of time between retries.
  final Duration initialPauseBetweenRetries;

  /// The pause between retries is multiplied by this number with each attempt,
  /// causing it to grow exponentially.
  final num exponentialBackoffMultiplier;

  /// A function that determines whether a given HTTP status code should be
  /// retried.
  final TransientHttpStatusCodePredicate transientHttpStatusCodePredicate;

  /// Uses [defaultTransientHttpStatusCodes] to determine if the [statusCode] is
  /// transient.
  static bool defaultTransientHttpStatusCodePredicate(int statusCode) {
    return defaultTransientHttpStatusCodes.contains(statusCode);
  }

  /// Builds a [FetchStrategy] that operates using the properties of this
  /// builder.
  FetchStrategy build() {
    return (Uri uri, FetchFailure? failure) async {
      if (failure == null) {
        // First attempt. Just load.
        return FetchInstructions.attempt(
          uri: uri,
          timeout: timeout,
        );
      }

      final bool isRetriableFailure = (failure.httpStatusCode != null &&
              transientHttpStatusCodePredicate(failure.httpStatusCode!)) ||
          failure.originalException is io.SocketException;

      // If cannot retry, give up.
      if (!isRetriableFailure || // retrying will not help
          failure.totalDuration > totalFetchTimeout || // taking too long
          failure.attemptCount > maxAttempts) {
        // too many attempts
        return FetchInstructions.giveUp(uri: uri);
      }

      // Exponential back-off.
      final Duration pauseBetweenRetries = initialPauseBetweenRetries *
          math.pow(exponentialBackoffMultiplier, failure.attemptCount - 1);
      await Future<void>.delayed(pauseBetweenRetries);

      // Retry.
      return FetchInstructions.attempt(
        uri: uri,
        timeout: timeout,
      );
    };
  }
}
