import 'dart:async';

import 'package:flutter/material.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:marianum_mobile/widget/route_transition_gate.dart';

void main() {
  const gated = Key('gated-child');
  const placeholder = Key('gate-placeholder');

  Widget gatedPage() => Scaffold(
    body: RouteTransitionGate(
      placeholder: const SizedBox(key: placeholder),
      builder: (_) => const SizedBox(key: gated),
    ),
  );

  Future<void> pumpApp(WidgetTester tester) async {
    await tester.pumpWidget(
      MaterialApp(home: Builder(builder: (_) => const Scaffold())),
    );
  }

  NavigatorState navigator(WidgetTester tester) =>
      tester.state<NavigatorState>(find.byType(Navigator));

  testWidgets('shows placeholder during push, child once settled', (
    tester,
  ) async {
    await pumpApp(tester);
    unawaited(
      navigator(tester).push(MaterialPageRoute<void>(builder: (_) => gatedPage())),
    );
    await tester.pump();
    await tester.pump(const Duration(milliseconds: 50));

    expect(find.byKey(placeholder), findsOneWidget);
    expect(find.byKey(gated), findsNothing);

    await tester.pumpAndSettle();
    expect(find.byKey(gated), findsOneWidget);
    expect(find.byKey(placeholder), findsNothing);
  });

  testWidgets('swaps back to placeholder while the route pops', (tester) async {
    await pumpApp(tester);
    unawaited(
      navigator(tester).push(MaterialPageRoute<void>(builder: (_) => gatedPage())),
    );
    await tester.pumpAndSettle();
    expect(find.byKey(gated), findsOneWidget);

    navigator(tester).pop();
    await tester.pump();
    await tester.pump(const Duration(milliseconds: 50));

    expect(find.byKey(gated), findsNothing);
    expect(find.byKey(placeholder), findsOneWidget);
  });

  testWidgets('gates during a secondary transition and recovers after pop', (
    tester,
  ) async {
    await pumpApp(tester);
    unawaited(
      navigator(tester).push(MaterialPageRoute<void>(builder: (_) => gatedPage())),
    );
    await tester.pumpAndSettle();
    expect(find.byKey(gated), findsOneWidget);

    unawaited(
      navigator(tester).push(MaterialPageRoute<void>(builder: (_) => const Scaffold())),
    );
    await tester.pump();
    await tester.pump(const Duration(milliseconds: 50));
    // Mid secondary transition the fragile subtree must be unmounted.
    expect(find.byKey(gated), findsNothing);

    await tester.pumpAndSettle();
    navigator(tester).pop();
    await tester.pumpAndSettle();
    // Back at rest on the gated route: child is mounted again.
    expect(find.byKey(gated), findsOneWidget);
    expect(find.byKey(placeholder), findsNothing);
  });
}
