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

void main() {

  test('ButtonBarThemeData null fields by default', () {
    const ButtonBarThemeData buttonBarTheme = ButtonBarThemeData();
    expect(buttonBarTheme.alignment, null);
    expect(buttonBarTheme.mainAxisSize, null);
    expect(buttonBarTheme.buttonTextTheme, null);
    expect(buttonBarTheme.buttonMinWidth, null);
    expect(buttonBarTheme.buttonHeight, null);
    expect(buttonBarTheme.buttonPadding, null);
    expect(buttonBarTheme.buttonAlignedDropdown, null);
    expect(buttonBarTheme.layoutBehavior, null);
    expect(buttonBarTheme.overflowDirection, null);
  });

  test('ThemeData uses default ButtonBarThemeData', () {
    expect(ThemeData().buttonBarTheme, equals(const ButtonBarThemeData()));
  });

  test('ButtonBarThemeData copyWith, ==, hashCode basics', () {
    expect(const ButtonBarThemeData(), const ButtonBarThemeData().copyWith());
    expect(const ButtonBarThemeData().hashCode, const ButtonBarThemeData().copyWith().hashCode);
  });

  testWidgets('ButtonBarThemeData lerps correctly', (WidgetTester tester) async {
    const ButtonBarThemeData barThemePrimary = ButtonBarThemeData(
      alignment: MainAxisAlignment.end,
      mainAxisSize: MainAxisSize.min,
      buttonTextTheme: ButtonTextTheme.primary,
      buttonMinWidth: 20.0,
      buttonHeight: 20.0,
      buttonPadding: EdgeInsets.symmetric(vertical: 5.0),
      buttonAlignedDropdown: false,
      layoutBehavior: ButtonBarLayoutBehavior.padded,
      overflowDirection: VerticalDirection.down,
    );
    const ButtonBarThemeData barThemeAccent = ButtonBarThemeData(
      alignment: MainAxisAlignment.center,
      mainAxisSize: MainAxisSize.max,
      buttonTextTheme: ButtonTextTheme.accent,
      buttonMinWidth: 10.0,
      buttonHeight: 40.0,
      buttonPadding: EdgeInsets.symmetric(horizontal: 10.0),
      buttonAlignedDropdown: true,
      layoutBehavior: ButtonBarLayoutBehavior.constrained,
      overflowDirection: VerticalDirection.up,
    );

    final ButtonBarThemeData lerp = ButtonBarThemeData.lerp(barThemePrimary, barThemeAccent, 0.5)!;
    expect(lerp.alignment, equals(MainAxisAlignment.center));
    expect(lerp.mainAxisSize, equals(MainAxisSize.max));
    expect(lerp.buttonTextTheme, equals(ButtonTextTheme.accent));
    expect(lerp.buttonMinWidth, equals(15.0));
    expect(lerp.buttonHeight, equals(30.0));
    expect(lerp.buttonPadding, equals(const EdgeInsets.fromLTRB(5.0, 2.5, 5.0, 2.5)));
    expect(lerp.buttonAlignedDropdown, isTrue);
    expect(lerp.layoutBehavior, equals(ButtonBarLayoutBehavior.constrained));
    expect(lerp.overflowDirection, equals(VerticalDirection.up));
  });

  testWidgets('Default ButtonBarThemeData debugFillProperties', (WidgetTester tester) async {
    final DiagnosticPropertiesBuilder builder = DiagnosticPropertiesBuilder();
    const ButtonBarThemeData().debugFillProperties(builder);

    final List<String> description = builder.properties
        .where((DiagnosticsNode node) => !node.isFiltered(DiagnosticLevel.info))
        .map((DiagnosticsNode node) => node.toString())
        .toList();

    expect(description, <String>[]);
  });

  testWidgets('ButtonBarThemeData implements debugFillProperties', (WidgetTester tester) async {
    final DiagnosticPropertiesBuilder builder = DiagnosticPropertiesBuilder();
    const ButtonBarThemeData(
      alignment: MainAxisAlignment.center,
      mainAxisSize: MainAxisSize.max,
      buttonTextTheme: ButtonTextTheme.accent,
      buttonMinWidth: 10.0,
      buttonHeight: 42.0,
      buttonPadding: EdgeInsets.symmetric(horizontal: 7.3),
      buttonAlignedDropdown: true,
      layoutBehavior: ButtonBarLayoutBehavior.constrained,
      overflowDirection: VerticalDirection.up,
    ).debugFillProperties(builder);

    final List<String> description = builder.properties
        .where((DiagnosticsNode node) => !node.isFiltered(DiagnosticLevel.info))
        .map((DiagnosticsNode node) => node.toString())
        .toList();

    expect(description, <String>[
      'alignment: MainAxisAlignment.center',
      'mainAxisSize: MainAxisSize.max',
      'textTheme: ButtonTextTheme.accent',
      'minWidth: 10.0',
      'height: 42.0',
      'padding: EdgeInsets(7.3, 0.0, 7.3, 0.0)',
      'dropdown width matches button',
      'layoutBehavior: ButtonBarLayoutBehavior.constrained',
      'overflowDirection: VerticalDirection.up',
    ]);
  });

  testWidgets('ButtonBarTheme.of falls back to ThemeData.buttonBarTheme', (WidgetTester tester) async {
    const ButtonBarThemeData buttonBarTheme = ButtonBarThemeData(buttonMinWidth: 42.0);
    late BuildContext capturedContext;
    await tester.pumpWidget(
      MaterialApp(
        theme: ThemeData(buttonBarTheme: buttonBarTheme),
        home: Builder(
          builder: (BuildContext context) {
            capturedContext = context;
            return Container();
          },
        ),
      ),
    );
    expect(ButtonBarTheme.of(capturedContext), equals(buttonBarTheme));
    expect(ButtonBarTheme.of(capturedContext).buttonMinWidth, equals(42.0));
  });

  testWidgets('ButtonBarTheme overrides ThemeData.buttonBarTheme', (WidgetTester tester) async {
    const ButtonBarThemeData defaultBarTheme = ButtonBarThemeData(buttonMinWidth: 42.0);
    const ButtonBarThemeData buttonBarTheme = ButtonBarThemeData(buttonMinWidth: 84.0);
    late BuildContext capturedContext;
    await tester.pumpWidget(
      MaterialApp(
        theme: ThemeData(buttonBarTheme: defaultBarTheme),
        home: Builder(
          builder: (BuildContext context) {
            return ButtonBarTheme(
              data: buttonBarTheme,
              child: Builder(
                builder: (BuildContext context) {
                  capturedContext = context;
                  return Container();
                },
              ),
            );
          },
        ),
      ),
    );
    expect(ButtonBarTheme.of(capturedContext), equals(buttonBarTheme));
    expect(ButtonBarTheme.of(capturedContext).buttonMinWidth, equals(84.0));
  });
}
