// 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 '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');
  }
}
