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

// @dart = 2.8

import 'dart:async';

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

import 'restoration.dart';

void main() {
  final TestAutomatedTestWidgetsFlutterBinding binding = TestAutomatedTestWidgetsFlutterBinding();

  setUp(() {
    binding._restorationManager = MockRestorationManager();
  });

  testWidgets('does not inject root bucket if inside scope', (WidgetTester tester) async {
    final MockRestorationManager manager = MockRestorationManager();
    final Map<String, dynamic> rawData = <String, dynamic>{};
    final RestorationBucket root = RestorationBucket.root(manager: manager, rawData: rawData);
    expect(rawData, isEmpty);

    await tester.pumpWidget(
      Directionality(
        textDirection: TextDirection.ltr,
        child: UnmanagedRestorationScope(
          bucket: root,
          child: const RootRestorationScope(
            restorationId: 'root-child',
            child: BucketSpy(
              child: Text('Hello'),
            ),
          ),
        ),
      ),
    );
    manager.doSerialization();

    expect(binding.restorationManager.rootBucketAccessed, 0);
    final BucketSpyState state = tester.state(find.byType(BucketSpy));
    expect(state.bucket.restorationId, 'root-child');
    expect(rawData[childrenMapKey].containsKey('root-child'), isTrue);

    expect(find.text('Hello'), findsOneWidget);
  });

  testWidgets('waits for root bucket', (WidgetTester tester) async {
    final Completer<RestorationBucket> bucketCompleter = Completer<RestorationBucket>();
    binding.restorationManager.rootBucket = bucketCompleter.future;

    await tester.pumpWidget(
      const Directionality(
        textDirection: TextDirection.ltr,
        child: RootRestorationScope(
          restorationId: 'root-child',
          child: BucketSpy(
            child: Text('Hello'),
          ),
        ),
      ),
    );

    expect(binding.restorationManager.rootBucketAccessed, 1);
    // Child rendering is delayed until root bucket is available.
    expect(find.text('Hello'), findsNothing);
    expect(binding.firstFrameIsDeferred, isTrue);

    // Complete the future.
    final Map<String, dynamic> rawData = <String, dynamic>{};
    final RestorationBucket root = RestorationBucket.root(manager: binding.restorationManager, rawData: rawData);
    bucketCompleter.complete(root);
    await tester.pump(const Duration(milliseconds: 100));

    expect(binding.restorationManager.rootBucketAccessed, 1);
    expect(find.text('Hello'), findsOneWidget);
    expect(binding.firstFrameIsDeferred, isFalse);

    final BucketSpyState state = tester.state(find.byType(BucketSpy));
    expect(state.bucket.restorationId, 'root-child');
    expect(rawData[childrenMapKey].containsKey('root-child'), isTrue);
  });

  testWidgets('no delay when root is available synchronously', (WidgetTester tester) async {
    final Map<String, dynamic> rawData = <String, dynamic>{};
    final RestorationBucket root = RestorationBucket.root(manager: binding.restorationManager, rawData: rawData);
    binding.restorationManager.rootBucket = SynchronousFuture<RestorationBucket>(root);

    await tester.pumpWidget(
      const Directionality(
        textDirection: TextDirection.ltr,
        child: RootRestorationScope(
          restorationId: 'root-child',
          child: BucketSpy(
            child: Text('Hello'),
          ),
        ),
      ),
    );

    expect(binding.restorationManager.rootBucketAccessed, 1);
    expect(find.text('Hello'), findsOneWidget);
    expect(binding.firstFrameIsDeferred, isFalse);

    final BucketSpyState state = tester.state(find.byType(BucketSpy));
    expect(state.bucket.restorationId, 'root-child');
    expect(rawData[childrenMapKey].containsKey('root-child'), isTrue);
  });

  testWidgets('does not insert root when restoration id is null', (WidgetTester tester) async {
    await tester.pumpWidget(
      const Directionality(
        textDirection: TextDirection.ltr,
        child: RootRestorationScope(
          restorationId: null,
          child: BucketSpy(
            child: Text('Hello'),
          ),
        ),
      ),
    );

    expect(binding.restorationManager.rootBucketAccessed, 0);
    expect(find.text('Hello'), findsOneWidget);
    expect(binding.firstFrameIsDeferred, isFalse);

    final BucketSpyState state = tester.state(find.byType(BucketSpy));
    expect(state.bucket, isNull);

    // Change restoration id to non-null.
    final Completer<RestorationBucket> bucketCompleter = Completer<RestorationBucket>();
    binding.restorationManager.rootBucket = bucketCompleter.future;
    await tester.pumpWidget(
      const Directionality(
        textDirection: TextDirection.ltr,
        child: RootRestorationScope(
          restorationId: 'root-child',
          child: BucketSpy(
            child: Text('Hello'),
          ),
        ),
      ),
    );

    expect(binding.restorationManager.rootBucketAccessed, 1);
    expect(find.text('Hello'), findsOneWidget);
    expect(state.bucket, isNull); // root bucket future has not completed yet.

    // Complete the future.
    final RestorationBucket root = RestorationBucket.root(manager: binding.restorationManager, rawData: <String, dynamic>{});
    bucketCompleter.complete(root);
    await tester.pump(const Duration(milliseconds: 100));

    expect(binding.restorationManager.rootBucketAccessed, 1);
    expect(find.text('Hello'), findsOneWidget);
    expect(state.bucket.restorationId, 'root-child');

    // Change ID back to null.
    await tester.pumpWidget(
      const Directionality(
        textDirection: TextDirection.ltr,
        child: RootRestorationScope(
          restorationId: null,
          child: BucketSpy(
            child: Text('Hello'),
          ),
        ),
      ),
    );

    expect(binding.restorationManager.rootBucketAccessed, 1);
    expect(find.text('Hello'), findsOneWidget);
    expect(state.bucket, isNull);
  });

  testWidgets('injects root bucket when moved out of scope', (WidgetTester tester) async {
    final Key rootScopeKey = GlobalKey();
    final MockRestorationManager manager = MockRestorationManager();
    final Map<String, dynamic> inScopeRawData = <String, dynamic>{};
    final RestorationBucket inScopeRootBucket = RestorationBucket.root(manager: manager, rawData: inScopeRawData);

    await tester.pumpWidget(
      Directionality(
        textDirection: TextDirection.ltr,
        child: UnmanagedRestorationScope(
          bucket: inScopeRootBucket,
          child: RootRestorationScope(
            key: rootScopeKey,
            restorationId: 'root-child',
            child: const BucketSpy(
              child: Text('Hello'),
            ),
          ),
        ),
      ),
    );

    expect(binding.restorationManager.rootBucketAccessed, 0);
    expect(find.text('Hello'), findsOneWidget);
    final BucketSpyState state = tester.state(find.byType(BucketSpy));
    expect(state.bucket.restorationId, 'root-child');
    expect(inScopeRawData[childrenMapKey].containsKey('root-child'), isTrue);

    // Move out of scope.
    final Completer<RestorationBucket> bucketCompleter = Completer<RestorationBucket>();
    binding.restorationManager.rootBucket = bucketCompleter.future;
    await tester.pumpWidget(
      Directionality(
        textDirection: TextDirection.ltr,
        child: RootRestorationScope(
          key: rootScopeKey,
          restorationId: 'root-child',
          child: const BucketSpy(
            child: Text('Hello'),
          ),
        ),
      ),
    );

    expect(binding.restorationManager.rootBucketAccessed, 1);
    expect(find.text('Hello'), findsOneWidget);

    final Map<String, dynamic> outOfScopeRawData = <String, dynamic>{};
    final RestorationBucket outOfScopeRootBucket = RestorationBucket.root(manager: binding.restorationManager, rawData: outOfScopeRawData);
    bucketCompleter.complete(outOfScopeRootBucket);
    await tester.pump(const Duration(milliseconds: 100));

    expect(binding.restorationManager.rootBucketAccessed, 1);
    expect(find.text('Hello'), findsOneWidget);
    expect(state.bucket.restorationId, 'root-child');
    expect(outOfScopeRawData[childrenMapKey].containsKey('root-child'), isTrue);
    expect(inScopeRawData, isEmpty);

    // Move into scope.
    await tester.pumpWidget(
      Directionality(
        textDirection: TextDirection.ltr,
        child: UnmanagedRestorationScope(
          bucket: inScopeRootBucket,
          child: RootRestorationScope(
            key: rootScopeKey,
            restorationId: 'root-child',
            child: const BucketSpy(
              child: Text('Hello'),
            ),
          ),
        ),
      ),
    );

    expect(binding.restorationManager.rootBucketAccessed, 1);
    expect(find.text('Hello'), findsOneWidget);
    expect(state.bucket.restorationId, 'root-child');
    expect(outOfScopeRawData, isEmpty);
    expect(inScopeRawData[childrenMapKey].containsKey('root-child'), isTrue);
  });

  testWidgets('injects new root when old one is decommissioned', (WidgetTester tester) async {
    final Map<String, dynamic> firstRawData = <String, dynamic>{};
    final RestorationBucket firstRoot = RestorationBucket.root(manager: binding.restorationManager, rawData: firstRawData);
    binding.restorationManager.rootBucket = SynchronousFuture<RestorationBucket>(firstRoot);

    await tester.pumpWidget(
      const Directionality(
        textDirection: TextDirection.ltr,
        child: RootRestorationScope(
          restorationId: 'root-child',
          child: BucketSpy(
            child: Text('Hello'),
          ),
        ),
      ),
    );

    expect(binding.restorationManager.rootBucketAccessed, 1);
    expect(find.text('Hello'), findsOneWidget);
    final BucketSpyState state = tester.state(find.byType(BucketSpy));
    state.bucket.write('foo', 42);
    expect(firstRawData[childrenMapKey]['root-child'][valuesMapKey]['foo'], 42);
    final RestorationBucket firstBucket = state.bucket;

    // Replace with new root.
    final Map<String, dynamic> secondRawData = <String, dynamic>{
      childrenMapKey: <String, dynamic>{
        'root-child': <String, dynamic>{
          valuesMapKey: <String, dynamic>{
            'foo': 22,
          },
        },
      },
    };
    final RestorationBucket secondRoot = RestorationBucket.root(manager: binding.restorationManager, rawData: secondRawData);
    binding.restorationManager.rootBucket = SynchronousFuture<RestorationBucket>(secondRoot);
    await tester.pump();
    firstRoot.dispose();

    expect(state.bucket, isNot(same(firstBucket)));
    expect(state.bucket.read<int>('foo'), 22);
  });

  testWidgets('injects null when rootBucket is null', (WidgetTester tester) async {
    final Completer<RestorationBucket> completer = Completer<RestorationBucket>();
    binding.restorationManager.rootBucket = completer.future;

    await tester.pumpWidget(
      const Directionality(
        textDirection: TextDirection.ltr,
        child: RootRestorationScope(
          restorationId: 'root-child',
          child: BucketSpy(
            child: Text('Hello'),
          ),
        ),
      ),
    );

    expect(binding.restorationManager.rootBucketAccessed, 1);
    expect(find.text('Hello'), findsNothing);

    completer.complete(null);
    await tester.pump(const Duration(milliseconds: 100));

    expect(binding.restorationManager.rootBucketAccessed, 1);
    expect(find.text('Hello'), findsOneWidget);

    final BucketSpyState state = tester.state(find.byType(BucketSpy));
    expect(state.bucket, isNull);

    final RestorationBucket root = RestorationBucket.root(manager: binding.restorationManager, rawData: null);
    binding.restorationManager.rootBucket = SynchronousFuture<RestorationBucket>(root);
    await tester.pump();

    expect(binding.restorationManager.rootBucketAccessed, 2);
    expect(find.text('Hello'), findsOneWidget);
    expect(state.bucket, isNotNull);
  });

  testWidgets('can switch to null', (WidgetTester tester) async {
    final RestorationBucket root = RestorationBucket.root(manager: binding.restorationManager, rawData: null);
    binding.restorationManager.rootBucket = SynchronousFuture<RestorationBucket>(root);

    await tester.pumpWidget(
      const Directionality(
        textDirection: TextDirection.ltr,
        child: RootRestorationScope(
          restorationId: 'root-child',
          child: BucketSpy(
            child: Text('Hello'),
          ),
        ),
      ),
    );

    expect(binding.restorationManager.rootBucketAccessed, 1);
    expect(find.text('Hello'), findsOneWidget);
    final BucketSpyState state = tester.state(find.byType(BucketSpy));
    expect(state.bucket, isNotNull);

    binding.restorationManager.rootBucket = SynchronousFuture<RestorationBucket>(null);
    await tester.pump();
    root.dispose();

    expect(binding.restorationManager.rootBucketAccessed, 2);
    expect(find.text('Hello'), findsOneWidget);
    expect(state.bucket, isNull);
  });
}

class TestAutomatedTestWidgetsFlutterBinding extends AutomatedTestWidgetsFlutterBinding {
  MockRestorationManager _restorationManager;

  @override
  MockRestorationManager get restorationManager => _restorationManager;

  @override
  TestRestorationManager createRestorationManager() {
    return null;
  }

  int _deferred = 0;

  bool get firstFrameIsDeferred => _deferred > 0;

  @override
  void deferFirstFrame() {
    _deferred++;
    super.deferFirstFrame();
  }

  @override
  void allowFirstFrame() {
    _deferred--;
    super.allowFirstFrame();
  }
}
