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

import 'dart:typed_data';

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

/// The [RestorationManager] used for tests.
///
/// Unlike the real [RestorationManager], this one just keeps the restoration
/// data in memory and does not make it available to the engine.
class TestRestorationManager extends RestorationManager {
  /// Creates a [TestRestorationManager].
  TestRestorationManager() {
    // Ensures that [rootBucket] always returns a synchronous future to avoid
    // extra pumps in tests.
    restoreFrom(TestRestorationData.empty);
  }

  @override
  Future<RestorationBucket> get rootBucket {
    _debugRootBucketAccessed = true;
    return super.rootBucket;
  }

  /// The current restoration data from which the current state can be restored.
  ///
  /// To restore the state to the one described by this data, pass the
  /// [TestRestorationData] obtained from this getter back to [restoreFrom].
  ///
  /// See also:
  ///
  ///  * [WidgetTester.getRestorationData], which makes this data available
  ///    in a widget test.
  TestRestorationData get restorationData => _restorationData;
  TestRestorationData _restorationData;

  /// Whether the [rootBucket] has been obtained.
  bool get debugRootBucketAccessed => _debugRootBucketAccessed;
  bool _debugRootBucketAccessed = false;

  /// Restores the state from the provided [TestRestorationData].
  ///
  /// The restoration data obtained form [restorationData] can be passed into
  /// this method to restore the state to what it was when the restoration data
  /// was originally retrieved.
  ///
  /// See also:
  ///
  ///  * [WidgetTester.restoreFrom], which exposes this method to a widget test.
  void restoreFrom(TestRestorationData data) {
    _restorationData = data;
    handleRestorationUpdateFromEngine(enabled: true, data: data.binary);
  }

  /// Disabled state restoration.
  ///
  /// To turn restoration back on call [restoreFrom].
  void disableRestoration() {
    _restorationData = null;
    handleRestorationUpdateFromEngine(enabled: false, data: null);
  }

  @override
  Future<void> sendToEngine(Uint8List encodedData) async {
    _restorationData = TestRestorationData._(encodedData);
  }
}

/// Restoration data that can be used to restore the state to the one described
/// by this data.
///
/// See also:
///
///  * [WidgetTester.getRestorationData], which retrieves the restoration data
///    from the widget under test.
///  * [WidgetTester.restoreFrom], which takes a [TestRestorationData] to
///    restore the state of the widget under test from the provided data.
class TestRestorationData {
  const TestRestorationData._(this.binary);

  /// Empty restoration data indicating that no data is available to restore
  /// state from.
  static const TestRestorationData empty = TestRestorationData._(null);

  /// The serialized representation of the restoration data.
  ///
  /// Should only be accessed by the test framework.
  @protected
  final Uint8List binary;
}
