import 'package:tane/ui/edge_fade.dart';
import 'package:flutter/material.dart';
import 'package:flutter_test/flutter_test.dart';

void main() {
  // A horizontal strip of [count] fixed-width boxes inside an EdgeFade-wrapped
  // SingleChildScrollView, laid out at the default 800px test surface width.
  Widget harness({
    required int count,
    TextDirection direction = TextDirection.ltr,
    ScrollController? controller,
  }) {
    return Directionality(
      textDirection: direction,
      child: EdgeFade(
        child: SingleChildScrollView(
          controller: controller,
          scrollDirection: Axis.horizontal,
          child: Row(
            children: [
              for (var i = 0; i < count; i++)
                const SizedBox(width: 100, height: 40),
            ],
          ),
        ),
      ),
    );
  }

  EdgeFadeState state(WidgetTester tester) =>
      tester.state<EdgeFadeState>(find.byType(EdgeFade));

  testWidgets('no fade on either edge when content fits', (tester) async {
    await tester.pumpWidget(harness(count: 3)); // 300px < 800px
    await tester.pump(); // let the post-layout metrics notification land
    expect(state(tester).fadeLeft, isFalse);
    expect(state(tester).fadeRight, isFalse);
    expect(find.byIcon(Icons.chevron_left), findsNothing);
    expect(find.byIcon(Icons.chevron_right), findsNothing);
  });

  testWidgets('a trailing chevron cue appears when the row overflows',
      (tester) async {
    await tester.pumpWidget(harness(count: 20));
    await tester.pump();
    expect(find.byIcon(Icons.chevron_right), findsOneWidget);
    expect(find.byIcon(Icons.chevron_left), findsNothing);
  });

  testWidgets('LTR: at start only the trailing (right) edge fades',
      (tester) async {
    await tester.pumpWidget(harness(count: 20)); // 2000px > 800px
    await tester.pump();
    expect(state(tester).fadeLeft, isFalse);
    expect(state(tester).fadeRight, isTrue);
  });

  testWidgets('LTR: in the middle both edges fade', (tester) async {
    final controller = ScrollController();
    addTearDown(controller.dispose);
    await tester.pumpWidget(harness(count: 20, controller: controller));
    await tester.pump();
    controller.jumpTo(600);
    await tester.pump();
    expect(state(tester).fadeLeft, isTrue);
    expect(state(tester).fadeRight, isTrue);
  });

  testWidgets('LTR: at the end only the leading (left) edge fades',
      (tester) async {
    final controller = ScrollController();
    addTearDown(controller.dispose);
    await tester.pumpWidget(harness(count: 20, controller: controller));
    await tester.pump();
    controller.jumpTo(controller.position.maxScrollExtent);
    await tester.pump();
    expect(state(tester).fadeLeft, isTrue);
    expect(state(tester).fadeRight, isFalse);
  });

  testWidgets('RTL: at start only the LEFT edge fades (mirrored)',
      (tester) async {
    await tester
        .pumpWidget(harness(count: 20, direction: TextDirection.rtl));
    await tester.pump();
    expect(state(tester).fadeLeft, isTrue);
    expect(state(tester).fadeRight, isFalse);
  });

  testWidgets('RTL: at the end only the RIGHT edge fades (mirrored)',
      (tester) async {
    final controller = ScrollController();
    addTearDown(controller.dispose);
    await tester.pumpWidget(harness(
      count: 20,
      direction: TextDirection.rtl,
      controller: controller,
    ));
    await tester.pump();
    controller.jumpTo(controller.position.maxScrollExtent);
    await tester.pump();
    expect(state(tester).fadeLeft, isFalse);
    expect(state(tester).fadeRight, isTrue);
  });

  testWidgets('RTL: no fade when content fits', (tester) async {
    await tester.pumpWidget(harness(count: 3, direction: TextDirection.rtl));
    await tester.pump();
    expect(state(tester).fadeLeft, isFalse);
    expect(state(tester).fadeRight, isFalse);
  });

  testWidgets('fades clear when content shrinks to fit', (tester) async {
    await tester.pumpWidget(harness(count: 20));
    await tester.pump();
    expect(state(tester).fadeRight, isTrue);

    await tester.pumpWidget(harness(count: 3));
    await tester.pump();
    expect(state(tester).fadeLeft, isFalse);
    expect(state(tester).fadeRight, isFalse);
  });

  testWidgets('scrolling by drag updates the fades', (tester) async {
    await tester.pumpWidget(harness(count: 20));
    await tester.pump();
    expect(state(tester).fadeLeft, isFalse);

    await tester.drag(
        find.byType(SingleChildScrollView), const Offset(-300, 0));
    await tester.pump();
    expect(state(tester).fadeLeft, isTrue);
    expect(state(tester).fadeRight, isTrue);
  });
}
