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

// This returns render paragraph of the Tab label text.
RenderParagraph getTabText(WidgetTester tester, String text) {
  return tester.renderObject<RenderParagraph>(find.descendant(
    of: find.byWidgetPredicate((Widget widget) => widget.runtimeType.toString() == '_TabStyle'),
    matching: find.text(text),
  ));
}

// This creates and returns a TabController.
TabController createTabController({
  required int length,
  required TickerProvider vsync,
  int initialIndex = 0,
  Duration? animationDuration,
}) {
  final TabController result = TabController(
    length: length,
    vsync: vsync,
    initialIndex: initialIndex,
    animationDuration: animationDuration,
  );
  addTearDown(result.dispose);
  return result;
}

// This widget is used to test widget state in the tabs_test.dart file.
class TabStateMarker extends StatefulWidget {
  const TabStateMarker({ super.key, this.child });

  final Widget? child;

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

class TabStateMarkerState extends State<TabStateMarker> {
  String? marker;

  @override
  Widget build(BuildContext context) {
    return widget.child ?? Container();
  }
}

// Tab controller builder for TabControllerFrame widget.
typedef TabControllerFrameBuilder = Widget Function(BuildContext context, TabController controller);

// This widget creates a TabController and passes it to the builder.
class TabControllerFrame extends StatefulWidget {
  const TabControllerFrame({
    super.key,
    required this.length,
    this.initialIndex = 0,
    required this.builder,
  });

  final int length;
  final int initialIndex;
  final TabControllerFrameBuilder builder;

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

class TabControllerFrameState extends State<TabControllerFrame> with SingleTickerProviderStateMixin {
  late TabController _controller;

  @override
  void initState() {
    super.initState();
    _controller = TabController(
      vsync: this,
      length: widget.length,
      initialIndex: widget.initialIndex,
    );
  }

  @override
  void dispose() {
    _controller.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return widget.builder(context, _controller);
  }
}

// Test utility class to test tab indicator drawing.
class TabIndicatorRecordingCanvas extends TestRecordingCanvas {
  TabIndicatorRecordingCanvas(this.indicatorColor);

  final Color indicatorColor;
  late Rect indicatorRect;

  @override
  void drawLine(Offset p1, Offset p2, Paint paint) {
    // Assuming that the indicatorWeight is 2.0, the default.
    const double indicatorWeight = 2.0;
    if (paint.color == indicatorColor) {
      indicatorRect = Rect.fromPoints(p1, p2).inflate(indicatorWeight / 2.0);
    }
  }
}

// This creates a Fake implementation of ScrollMetrics.
class TabMockScrollMetrics extends Fake implements ScrollMetrics { }

class TabBarTestScrollPhysics extends ScrollPhysics {
  const TabBarTestScrollPhysics({ super.parent });

  @override
  TabBarTestScrollPhysics applyTo(ScrollPhysics? ancestor) {
    return TabBarTestScrollPhysics(parent: buildParent(ancestor));
  }

  @override
  double applyPhysicsToUserOffset(ScrollMetrics position, double offset) {
    return offset == 10 ? 20 : offset;
  }

  static final SpringDescription _kDefaultSpring = SpringDescription.withDampingRatio(
    mass: 0.5,
    stiffness: 500.0,
    ratio: 1.1,
  );

  @override
  SpringDescription get spring => _kDefaultSpring;
}

// This widget is used to log the lifecycle of the TabBarView children.
class TabBody extends StatefulWidget {
  const TabBody({
    super.key,
    required this.index,
    required this.log,
    this.marker = '',
  });

  final int index;
  final List<String> log;
  final String marker;

  @override
  State<TabBody> createState() => TabBodyState();
}

class TabBodyState extends State<TabBody> {
  @override
  void initState() {
    widget.log.add('init: ${widget.index}');
    super.initState();
  }

  @override
  void didUpdateWidget(TabBody oldWidget) {
    super.didUpdateWidget(oldWidget);
    // To keep the logging straight, widgets must not change their index.
    assert(oldWidget.index == widget.index);
  }

  @override
  void dispose() {
    widget.log.add('dispose: ${widget.index}');
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return Center(
      child: widget.marker.isEmpty
        ? Text('${widget.index}')
        : Text('${widget.index}-${widget.marker}'),
    );
  }
}

// This widget is used to test the lifecycle of the TabBarView children with Ink widget.
class TabKeepAliveInk extends StatefulWidget {
  const TabKeepAliveInk({ super.key, required this.title });

  final String title;

  @override
  State<StatefulWidget> createState() => _TabKeepAliveInkState();
}

class _TabKeepAliveInkState extends State<TabKeepAliveInk> with AutomaticKeepAliveClientMixin {
  @override
  bool get wantKeepAlive => true;

  @override
  Widget build(BuildContext context) {
    super.build(context);
    return Ink(
      child: Text(widget.title),
    );
  }
}

// This widget is used to test the lifecycle of the TabBarView children.
class TabAlwaysKeepAliveWidget extends StatefulWidget {
  const TabAlwaysKeepAliveWidget({super.key});

  static String text = 'AlwaysKeepAlive';

  @override
  State<TabAlwaysKeepAliveWidget> createState() => _TabAlwaysKeepAliveWidgetState();
}

class _TabAlwaysKeepAliveWidgetState extends State<TabAlwaysKeepAliveWidget> with AutomaticKeepAliveClientMixin {
  @override
  bool get wantKeepAlive => true;

  @override
  Widget build(BuildContext context) {
    super.build(context);
    return Text(TabAlwaysKeepAliveWidget.text);
  }
}

// This decoration is used to test the indicator decoration image configuration.
class TestIndicatorDecoration extends Decoration {
  final List<TestIndicatorBoxPainter> painters = <TestIndicatorBoxPainter>[];

  @override
  BoxPainter createBoxPainter([VoidCallback? onChanged]) {
    final TestIndicatorBoxPainter painter = TestIndicatorBoxPainter();
    painters.add(painter);
    return painter;
  }
}

class TestIndicatorBoxPainter extends BoxPainter {
  ImageConfiguration? lastConfiguration;

  @override
  void paint(Canvas canvas, Offset offset, ImageConfiguration configuration) {
    lastConfiguration = configuration;
  }
}
