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

const String _actualContent = 'Actual Content';
const String _loading = 'Loading...';

void main() {
  testWidgets('deferFirstFrame/allowFirstFrame stops sending frames to engine', (WidgetTester tester) async {
    expect(RendererBinding.instance.sendFramesToEngine, isTrue);

    final Completer<void> completer = Completer<void>();
    await tester.pumpWidget(
      Directionality(
        textDirection: TextDirection.ltr,
        child: _DeferringWidget(
          key: UniqueKey(),
          loader: completer.future,
        ),
      ),
    );
    final _DeferringWidgetState state = tester.state<_DeferringWidgetState>(find.byType(_DeferringWidget));

    expect(find.text(_loading), findsOneWidget);
    expect(find.text(_actualContent), findsNothing);
    expect(RendererBinding.instance.sendFramesToEngine, isFalse);

    await tester.pump();
    expect(find.text(_loading), findsOneWidget);
    expect(find.text(_actualContent), findsNothing);
    expect(RendererBinding.instance.sendFramesToEngine, isFalse);
    expect(state.doneLoading, isFalse);

    // Complete the future to start sending frames.
    completer.complete();
    await tester.idle();
    expect(state.doneLoading, isTrue);
    expect(RendererBinding.instance.sendFramesToEngine, isTrue);

    await tester.pump();
    expect(find.text(_loading), findsNothing);
    expect(find.text(_actualContent), findsOneWidget);
    expect(RendererBinding.instance.sendFramesToEngine, isTrue);
  });

  testWidgets('Two widgets can defer frames', (WidgetTester tester) async {
    expect(RendererBinding.instance.sendFramesToEngine, isTrue);

    final Completer<void> completer1 = Completer<void>();
    final Completer<void> completer2 = Completer<void>();
    await tester.pumpWidget(
      Directionality(
        textDirection: TextDirection.ltr,
        child: Row(
          children: <Widget>[
            _DeferringWidget(
              key: UniqueKey(),
              loader: completer1.future,
            ),
            _DeferringWidget(
              key: UniqueKey(),
              loader: completer2.future,
            ),
          ],
        ),
      ),
    );
    expect(find.text(_loading), findsNWidgets(2));
    expect(find.text(_actualContent), findsNothing);
    expect(RendererBinding.instance.sendFramesToEngine, isFalse);

    completer1.complete();
    completer2.complete();
    await tester.idle();

    await tester.pump();
    expect(find.text(_loading), findsNothing);
    expect(find.text(_actualContent), findsNWidgets(2));
    expect(RendererBinding.instance.sendFramesToEngine, isTrue);
  });
}

class _DeferringWidget extends StatefulWidget {
  const _DeferringWidget({required Key key, required this.loader}) : super(key: key);

  final Future<void> loader;

  @override
  State<_DeferringWidget> createState() => _DeferringWidgetState();
}

class _DeferringWidgetState extends State<_DeferringWidget> {
  bool doneLoading = false;

  @override
  void initState() {
    super.initState();
    RendererBinding.instance.deferFirstFrame();
    widget.loader.then((_) {
      setState(() {
        doneLoading = true;
        RendererBinding.instance.allowFirstFrame();
      });
    });
  }

  @override
  Widget build(BuildContext context) {
    return doneLoading
        ? const Text(_actualContent)
        : const Text(_loading);
  }
}
