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

import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_test/flutter_test.dart';

void main() {
  group('SystemChrome - style', () {
    const double statusBarHeight = 25.0;
    const double navigationBarHeight = 54.0;
    const double deviceHeight = 960.0;
    const double deviceWidth = 480.0;
    const double devicePixelRatio = 2.0;

    void setupTestDevice() {
      final TestWidgetsFlutterBinding binding = TestWidgetsFlutterBinding.ensureInitialized();
      const FakeWindowPadding padding = FakeWindowPadding(
        top: statusBarHeight * devicePixelRatio,
        bottom: navigationBarHeight * devicePixelRatio,
      );

      binding.window
        ..viewPaddingTestValue = padding
        ..paddingTestValue = padding
        ..devicePixelRatioTestValue = devicePixelRatio
        ..physicalSizeTestValue = const Size(
          deviceWidth * devicePixelRatio,
          deviceHeight * devicePixelRatio,
        );
    }

    tearDown(() async {
      SystemChrome.setSystemUIOverlayStyle(const SystemUiOverlayStyle());
      await pumpEventQueue();
    });

    group('status bar', () {
      testWidgets(
        "statusBarColor isn't set for unannotated view",
        (WidgetTester tester) async {
          await tester.pumpWidget(const SizedBox.expand());
          await tester.pumpAndSettle();

          expect(SystemChrome.latestStyle?.statusBarColor, isNull);
        },
      );

      testWidgets(
        'statusBarColor is set for annotated view',
        (WidgetTester tester) async {
          setupTestDevice();
          await tester.pumpWidget(const AnnotatedRegion<SystemUiOverlayStyle>(
            value: SystemUiOverlayStyle(
              statusBarColor: Colors.blue,
            ),
            child: SizedBox.expand(),
          ));
          await tester.pumpAndSettle();

          expect(
            SystemChrome.latestStyle?.statusBarColor,
            Colors.blue,
          );
        },
        variant: TargetPlatformVariant.mobile(),
      );

      testWidgets(
        "statusBarColor isn't set when view covers less than half of the system status bar",
        (WidgetTester tester) async {
          setupTestDevice();
          const double lessThanHalfOfTheStatusBarHeight =
              statusBarHeight / 2.0 - 1;
          await tester.pumpWidget(const Align(
            alignment: Alignment.topCenter,
            child: AnnotatedRegion<SystemUiOverlayStyle>(
              value: SystemUiOverlayStyle(
                statusBarColor: Colors.blue,
              ),
              child: SizedBox(
                width: 100,
                height: lessThanHalfOfTheStatusBarHeight,
              ),
            ),
          ));
          await tester.pumpAndSettle();

          expect(SystemChrome.latestStyle?.statusBarColor, isNull);
        },
        variant: TargetPlatformVariant.mobile(),
      );

      testWidgets(
        'statusBarColor is set when view covers more than half of tye system status bar',
        (WidgetTester tester) async {
          setupTestDevice();
          const double moreThanHalfOfTheStatusBarHeight =
              statusBarHeight / 2.0 + 1;
          await tester.pumpWidget(const Align(
            alignment: Alignment.topCenter,
            child: AnnotatedRegion<SystemUiOverlayStyle>(
              value: SystemUiOverlayStyle(
                statusBarColor: Colors.blue,
              ),
              child: SizedBox(
                width: 100,
                height: moreThanHalfOfTheStatusBarHeight,
              ),
            ),
          ));
          await tester.pumpAndSettle();

          expect(
            SystemChrome.latestStyle?.statusBarColor,
            Colors.blue,
          );
        },
        variant: TargetPlatformVariant.mobile(),
      );
    });

    group('navigation color (Android only)', () {
      testWidgets(
        "systemNavigationBarColor isn't set for non Android device",
        (WidgetTester tester) async {
          setupTestDevice();
          await tester.pumpWidget(const AnnotatedRegion<SystemUiOverlayStyle>(
            value: SystemUiOverlayStyle(
              systemNavigationBarColor: Colors.blue,
            ),
            child: SizedBox.expand(),
          ));
          await tester.pumpAndSettle();

          expect(
            SystemChrome.latestStyle?.systemNavigationBarColor,
            isNull,
          );
        },
        variant: TargetPlatformVariant.only(TargetPlatform.iOS),
      );

      testWidgets(
        "systemNavigationBarColor isn't set for unannotated view",
        (WidgetTester tester) async {
          await tester.pumpWidget(const SizedBox.expand());
          await tester.pumpAndSettle();

          expect(SystemChrome.latestStyle?.systemNavigationBarColor, isNull);
        },
        variant: TargetPlatformVariant.only(TargetPlatform.android),
      );

      testWidgets(
        'systemNavigationBarColor is set for annotated view',
        (WidgetTester tester) async {
          setupTestDevice();
          await tester.pumpWidget(const AnnotatedRegion<SystemUiOverlayStyle>(
            value: SystemUiOverlayStyle(
              systemNavigationBarColor: Colors.blue,
            ),
            child: SizedBox.expand(),
          ));
          await tester.pumpAndSettle();

          expect(
            SystemChrome.latestStyle?.systemNavigationBarColor,
            Colors.blue,
          );
        },
        variant: TargetPlatformVariant.only(TargetPlatform.android),
      );

      testWidgets(
        "systemNavigationBarColor isn't set when view covers less than half of navigation bar",
        (WidgetTester tester) async {
          setupTestDevice();
          const double lessThanHalfOfTheNavigationBarHeight =
              navigationBarHeight / 2.0 - 1;
          await tester.pumpWidget(const Align(
            alignment: Alignment.bottomCenter,
            child: AnnotatedRegion<SystemUiOverlayStyle>(
              value: SystemUiOverlayStyle(
                systemNavigationBarColor: Colors.blue,
              ),
              child: SizedBox(
                width: 100,
                height: lessThanHalfOfTheNavigationBarHeight,
              ),
            ),
          ));
          await tester.pumpAndSettle();

          expect(SystemChrome.latestStyle?.systemNavigationBarColor, isNull);
        },
        variant: TargetPlatformVariant.only(TargetPlatform.android),
      );

      testWidgets(
        'systemNavigationBarColor is set when view covers more than half of navigation bar',
        (WidgetTester tester) async {
          setupTestDevice();
          const double moreThanHalfOfTheNavigationBarHeight =
              navigationBarHeight / 2.0 + 1;
          await tester.pumpWidget(const Align(
            alignment: Alignment.bottomCenter,
            child: AnnotatedRegion<SystemUiOverlayStyle>(
              value: SystemUiOverlayStyle(
                systemNavigationBarColor: Colors.blue,
              ),
              child: SizedBox(
                width: 100,
                height: moreThanHalfOfTheNavigationBarHeight,
              ),
            ),
          ));
          await tester.pumpAndSettle();

          expect(
            SystemChrome.latestStyle?.systemNavigationBarColor,
            Colors.blue,
          );
        },
        variant: TargetPlatformVariant.only(TargetPlatform.android),
      );
    });

    testWidgets('Top AnnotatedRegion provides status bar overlay style and bottom AnnotatedRegion provides navigation bar overlay style', (WidgetTester tester) async {
      setupTestDevice();
      await tester.pumpWidget(
        Column(children: const <Widget>[
          Expanded(child: AnnotatedRegion<SystemUiOverlayStyle>(
            value: SystemUiOverlayStyle(
              systemNavigationBarColor: Colors.blue,
              statusBarColor: Colors.blue
            ),
            child: SizedBox.expand(),
          )),
          Expanded(child: AnnotatedRegion<SystemUiOverlayStyle>(
            value: SystemUiOverlayStyle(
              systemNavigationBarColor: Colors.green,
              statusBarColor: Colors.green,
            ),
            child: SizedBox.expand(),
          )),
        ]),
      );
      await tester.pumpAndSettle();

      expect(SystemChrome.latestStyle?.statusBarColor, Colors.blue);
      expect(SystemChrome.latestStyle?.systemNavigationBarColor, Colors.green);
    }, variant: TargetPlatformVariant.only(TargetPlatform.android));

    testWidgets('Top only AnnotatedRegion provides status bar and navigation bar style properties', (WidgetTester tester) async {
      setupTestDevice();
      await tester.pumpWidget(
        Column(children: const <Widget>[
          Expanded(child: AnnotatedRegion<SystemUiOverlayStyle>(
            value: SystemUiOverlayStyle(
              systemNavigationBarColor: Colors.blue,
              statusBarColor: Colors.blue
            ),
            child: SizedBox.expand(),
          )),
          Expanded(child: SizedBox.expand()),
        ]),
      );
      await tester.pumpAndSettle();

      expect(SystemChrome.latestStyle?.statusBarColor, Colors.blue);
      expect(SystemChrome.latestStyle?.systemNavigationBarColor, Colors.blue);
    }, variant: TargetPlatformVariant.only(TargetPlatform.android));

    testWidgets('Bottom only AnnotatedRegion provides status bar and navigation bar style properties', (WidgetTester tester) async {
      setupTestDevice();
      await tester.pumpWidget(
        Column(children: const <Widget>[
          Expanded(child: SizedBox.expand()),
          Expanded(child: AnnotatedRegion<SystemUiOverlayStyle>(
            value: SystemUiOverlayStyle(
              systemNavigationBarColor: Colors.green,
              statusBarColor: Colors.green
            ),
            child: SizedBox.expand(),
          )),
        ]),
      );
      await tester.pumpAndSettle();

      expect(SystemChrome.latestStyle?.statusBarColor, Colors.green);
      expect(SystemChrome.latestStyle?.systemNavigationBarColor, Colors.green);
    }, variant: TargetPlatformVariant.only(TargetPlatform.android));
  });
}

class FakeWindowPadding implements WindowPadding {
  const FakeWindowPadding({
    this.left = 0.0,
    this.top = 0.0,
    this.right = 0.0,
    this.bottom = 0.0,
  });

  @override
  final double left;
  @override
  final double top;
  @override
  final double right;
  @override
  final double bottom;
}