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

// This is a regression test for https://github.com/flutter/flutter/issues/5840.

class Bar extends StatefulWidget {
  const Bar({ super.key });
  @override
  BarState createState() => BarState();
}

class BarState extends State<Bar> {
  final GlobalKey _fooKey = GlobalKey();

  bool _mode = false;

  void trigger() {
    setState(() {
      _mode = !_mode;
    });
  }

  @override
  Widget build(BuildContext context) {
    if (_mode) {
      return SizedBox(
        child: LayoutBuilder(
          builder: (BuildContext context, BoxConstraints constraints) {
            return StatefulCreationCounter(key: _fooKey);
          },
        ),
      );
    } else {
      return LayoutBuilder(
        builder: (BuildContext context, BoxConstraints constraints) {
          return StatefulCreationCounter(key: _fooKey);
        },
      );
    }
  }
}

class StatefulCreationCounter extends StatefulWidget {
  const StatefulCreationCounter({ super.key });

  @override
  StatefulCreationCounterState createState() => StatefulCreationCounterState();
}

class StatefulCreationCounterState extends State<StatefulCreationCounter> {
  static int creationCount = 0;

  @override
  void initState() {
    super.initState();
    creationCount += 1;
  }

  @override
  Widget build(BuildContext context) => Container();
}

void main() {
  testWidgets('reparent state with layout builder', (WidgetTester tester) async {
    expect(StatefulCreationCounterState.creationCount, 0);
    await tester.pumpWidget(const Bar());
    expect(StatefulCreationCounterState.creationCount, 1);
    final BarState s = tester.state<BarState>(find.byType(Bar));
    s.trigger();
    await tester.pump();
    expect(StatefulCreationCounterState.creationCount, 1);
  });

  testWidgets('Clean then reparent with dependencies', (WidgetTester tester) async {
    int layoutBuilderBuildCount = 0;

    late StateSetter keyedSetState;
    late StateSetter layoutBuilderSetState;
    late StateSetter childSetState;

    final GlobalKey key = GlobalKey();
    final Widget keyedWidget = StatefulBuilder(
      key: key,
      builder: (BuildContext context, StateSetter setState) {
        keyedSetState = setState;
        MediaQuery.of(context);
        return Container();
      },
    );

    Widget layoutBuilderChild = keyedWidget;
    Widget deepChild = Container();

    await tester.pumpWidget(MediaQuery(
      data: MediaQueryData.fromWindow(WidgetsBinding.instance.window),
      child: Column(
        children: <Widget>[
          StatefulBuilder(builder: (BuildContext context, StateSetter setState) {
            layoutBuilderSetState = setState;
            return LayoutBuilder(
              builder: (BuildContext context, BoxConstraints constraints) {
                layoutBuilderBuildCount += 1;
                return layoutBuilderChild; // initially keyedWidget above, but then a new Container
              },
            );
          }),
          Container(
            color: Colors.green,
            child: Container(
              color: Colors.green,
              child: Container(
                color: Colors.green,
                child: Container(
                  color: Colors.green,
                  child: Container(
                    color: Colors.green,
                    child: Container(
                      color: Colors.green,
                      child: StatefulBuilder(
                        builder: (BuildContext context, StateSetter setState) {
                          childSetState = setState;
                          return deepChild; // initially a Container, but then the keyedWidget above
                        },
                      ),
                    ),
                  ),
                ),
              ),
            ),
          ),
        ],
      ),
    ));
    expect(layoutBuilderBuildCount, 1);

    keyedSetState(() { /* Change nothing but add the element to the dirty list. */ });

    childSetState(() {
      // The deep child builds in the initial build phase. It takes the child
      // from the LayoutBuilder before the LayoutBuilder has a chance to build.
      deepChild = keyedWidget;
    });

    layoutBuilderSetState(() {
      // The layout builder will build in a separate build scope. This delays
      // the removal of the keyed child until this build scope.
      layoutBuilderChild = Container();
    });

    // The essential part of this test is that this call to pump doesn't throw.
    await tester.pump();
    expect(layoutBuilderBuildCount, 2);
  });
}
