// 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 'package:flutter/material.dart';
import 'package:flutter_test/flutter_test.dart';

void main() {
  testWidgets('widget moves scopes during restore', (WidgetTester tester) async {
    await tester.pumpWidget(RootRestorationScope(
      restorationId: 'root',
      child: Directionality(
        textDirection: TextDirection.ltr,
        child: TestWidgetWithCounterChild(),
      ),
    ));

    expect(tester.state<TestWidgetWithCounterChildState>(find.byType(TestWidgetWithCounterChild)).restoreChild, true);
    expect(find.text('Counter: 0'), findsOneWidget);
    await tester.tap(find.text('Counter: 0'));
    await tester.pump();
    expect(find.text('Counter: 1'), findsOneWidget);

    final TestRestorationData dataWithChild = await tester.getRestorationData();

    tester.state<TestWidgetWithCounterChildState>(find.byType(TestWidgetWithCounterChild)).restoreChild = false;
    await tester.pump();
    expect(tester.state<TestWidgetWithCounterChildState>(find.byType(TestWidgetWithCounterChild)).restoreChild, false);

    await tester.tap(find.text('Counter: 1'));
    await tester.pump();
    expect(find.text('Counter: 2'), findsOneWidget);

    final TestRestorationData dataWithoutChild = await tester.getRestorationData();

    // Child moves from outside to inside scope.
    await tester.restoreFrom(dataWithChild);
    expect(find.text('Counter: 1'), findsOneWidget);

    await tester.tap(find.text('Counter: 1'));
    await tester.pump();
    expect(find.text('Counter: 2'), findsOneWidget);

    // Child stays inside scope.
    await tester.restoreFrom(dataWithChild);
    expect(find.text('Counter: 1'), findsOneWidget);

    await tester.tap(find.text('Counter: 1'));
    await tester.tap(find.text('Counter: 1'));
    await tester.tap(find.text('Counter: 1'));
    await tester.tap(find.text('Counter: 1'));
    await tester.tap(find.text('Counter: 1'));
    await tester.pump();
    expect(find.text('Counter: 6'), findsOneWidget);

    // Child moves from inside to outside scope.
    await tester.restoreFrom(dataWithoutChild);
    expect(find.text('Counter: 6'), findsOneWidget);

    await tester.tap(find.text('Counter: 6'));
    await tester.pump();
    expect(find.text('Counter: 7'), findsOneWidget);

    // Child stays outside scope.
    await tester.restoreFrom(dataWithoutChild);
    expect(find.text('Counter: 7'), findsOneWidget);

    expect(tester.state<TestWidgetWithCounterChildState>(find.byType(TestWidgetWithCounterChild)).toggleCount, 0);
  });

  testWidgets('restoration is turned on later', (WidgetTester tester) async {
    tester.binding.restorationManager.disableRestoration();
    await tester.pumpWidget(const RootRestorationScope(
      restorationId: 'root-child',
      child: Directionality(
        textDirection: TextDirection.ltr,
        child: TestWidget(
          restorationId: 'foo',
        ),
      ),
    ));

    final TestWidgetState state = tester.state<TestWidgetState>(find.byType(TestWidget));
    expect(find.text('hello'), findsOneWidget);
    expect(state.buckets.single, isNull);
    expect(state.flags.single, isTrue);
    expect(state.bucket, isNull);

    state.buckets.clear();
    state.flags.clear();

    await tester.restoreFrom(TestRestorationData.empty);

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

    expect(find.text('hello'), findsOneWidget);
    expect(state.buckets.single, isNull);
    expect(state.flags.single, isFalse);
    expect(state.bucket, isNotNull);

    expect(state.toggleCount, 0);
  });
}

class TestWidgetWithCounterChild extends StatefulWidget {
  @override
  State<TestWidgetWithCounterChild> createState() => TestWidgetWithCounterChildState();
}

class TestWidgetWithCounterChildState extends State<TestWidgetWithCounterChild> with RestorationMixin {
  final RestorableBool childRestorationEnabled = RestorableBool(true);

  int toggleCount = 0;

  @override
  void didToggleBucket(RestorationBucket oldBucket) {
    super.didToggleBucket(oldBucket);
    toggleCount++;
  }

  @override
  void restoreState(RestorationBucket oldBucket, bool initialRestore) {
    registerForRestoration(childRestorationEnabled, 'childRestorationEnabled');
  }

  bool get restoreChild => childRestorationEnabled.value;
  set restoreChild(bool value) {
    if (value == childRestorationEnabled.value) {
      return;
    }
    setState(() {
      childRestorationEnabled.value = value;
    });
  }

  @override
  void dispose() {
    childRestorationEnabled.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return Counter(
      restorationId: restoreChild ? 'counter' : null,
    );
  }

  @override
  String get restorationId => 'foo';
}

class Counter extends StatefulWidget {
  const Counter({this.restorationId});

  final String restorationId;

  @override
  State<Counter> createState() => CounterState();
}

class CounterState extends State<Counter> with RestorationMixin {
  final RestorableInt count = RestorableInt(0);

  @override
  String get restorationId => widget.restorationId;

  @override
  void restoreState(RestorationBucket oldBucket, bool initialRestore) {
    registerForRestoration(count, 'counter');
  }

  @override
  void dispose() {
    count.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return OutlinedButton(
      onPressed: () {
        setState(() {
          count.value++;
        });
      },
      child: Text(
        'Counter: ${count.value}',
      ),
    );
  }
}

class TestWidget extends StatefulWidget {
  const TestWidget({@required this.restorationId});

  final String restorationId;

  @override
  State<TestWidget> createState() => TestWidgetState();
}

class TestWidgetState extends State<TestWidget> with RestorationMixin {
  List<RestorationBucket> buckets = <RestorationBucket>[];
  List<bool> flags = <bool>[];

  @override
  void restoreState(RestorationBucket oldBucket, bool initialRestore) {
    buckets.add(oldBucket);
    flags.add(initialRestore);
  }

  int toggleCount = 0;

  @override
  void didToggleBucket(RestorationBucket oldBucket) {
    super.didToggleBucket(oldBucket);
    toggleCount++;
  }

  @override
  String get restorationId => widget.restorationId;

  @override
  Widget build(BuildContext context) {
    return const Text('hello');
  }
}
