// 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: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 {
  late MockRestorationManager _restorationManager;

  @override
  MockRestorationManager get restorationManager => _restorationManager;

  @override
  TestRestorationManager createRestorationManager() {
    return TestRestorationManager();
  }

  int _deferred = 0;

  bool get firstFrameIsDeferred => _deferred > 0;

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

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