import 'package:flutter/gestures.dart';
import 'package:flutter/material.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:fluttersdk_wind/fluttersdk_wind.dart';

/// Helper to wrap widget in MaterialApp with WindTheme
Widget wrapWithTheme(Widget child) {
  return MaterialApp(
    home: WindTheme(
      data: WindThemeData(),
      child: Scaffold(body: child),
    ),
  );
}

void main() {
  group('WButton Widget Tests', () {
    group('Basic Rendering', () {
      testWidgets('renders child content', (tester) async {
        await tester.pumpWidget(
          wrapWithTheme(WButton(onTap: () {}, child: const Text('Click Me'))),
        );

        expect(find.text('Click Me'), findsOneWidget);
      });

      testWidgets('applies className styling', (tester) async {
        await tester.pumpWidget(
          wrapWithTheme(
            WButton(
              onTap: () {},
              className: 'bg-blue-500 p-4 rounded-lg',
              child: const Text('Styled'),
            ),
          ),
        );

        expect(find.byType(Container), findsOneWidget);
      });
    });

    group('Tap Interaction', () {
      testWidgets('calls onTap when pressed', (tester) async {
        bool wasTapped = false;

        await tester.pumpWidget(
          wrapWithTheme(
            WButton(onTap: () => wasTapped = true, child: const Text('Tap Me')),
          ),
        );

        await tester.tap(find.text('Tap Me'));
        await tester.pump();

        expect(wasTapped, isTrue);
      });

      testWidgets('calls onLongPress when long pressed', (tester) async {
        bool wasLongPressed = false;

        await tester.pumpWidget(
          wrapWithTheme(
            WButton(
              onLongPress: () => wasLongPressed = true,
              child: const Text('Long Press'),
            ),
          ),
        );

        await tester.longPress(find.text('Long Press'));
        await tester.pump();

        expect(wasLongPressed, isTrue);
      });
    });

    group('Disabled State', () {
      testWidgets('does not call onTap when disabled', (tester) async {
        bool wasTapped = false;

        await tester.pumpWidget(
          wrapWithTheme(
            WButton(
              onTap: () => wasTapped = true,
              disabled: true,
              child: const Text('Disabled'),
            ),
          ),
        );

        await tester.tap(find.text('Disabled'));
        await tester.pump();

        expect(wasTapped, isFalse);
      });

      testWidgets('applies disabled className styling', (tester) async {
        await tester.pumpWidget(
          wrapWithTheme(
            WButton(
              onTap: () {},
              disabled: true,
              className: 'bg-blue-500 disabled:bg-gray-400',
              child: const Text('Disabled'),
            ),
          ),
        );

        // Widget should render
        expect(find.text('Disabled'), findsOneWidget);
      });
    });

    group('Loading State', () {
      testWidgets('shows loading spinner when isLoading is true', (
        tester,
      ) async {
        await tester.pumpWidget(
          wrapWithTheme(
            WButton(onTap: () {}, isLoading: true, child: const Text('Submit')),
          ),
        );

        expect(find.byType(CircularProgressIndicator), findsOneWidget);
        expect(find.text('Submit'), findsNothing);
      });

      testWidgets('shows loadingText alongside spinner', (tester) async {
        await tester.pumpWidget(
          wrapWithTheme(
            WButton(
              onTap: () {},
              isLoading: true,
              loadingText: 'Loading...',
              child: const Text('Submit'),
            ),
          ),
        );

        expect(find.byType(CircularProgressIndicator), findsOneWidget);
        expect(find.text('Loading...'), findsOneWidget);
      });

      testWidgets('shows custom loadingWidget when provided', (tester) async {
        await tester.pumpWidget(
          wrapWithTheme(
            WButton(
              onTap: () {},
              isLoading: true,
              loadingWidget: const Icon(Icons.hourglass_empty),
              child: const Text('Submit'),
            ),
          ),
        );

        expect(find.byIcon(Icons.hourglass_empty), findsOneWidget);
        expect(find.byType(CircularProgressIndicator), findsNothing);
      });

      testWidgets('does not call onTap when loading', (tester) async {
        bool wasTapped = false;

        await tester.pumpWidget(
          wrapWithTheme(
            WButton(
              onTap: () => wasTapped = true,
              isLoading: true,
              child: const Text('Loading'),
            ),
          ),
        );

        // Try to tap the button container area (not the spinner directly)
        await tester.tap(find.byType(Container).first, warnIfMissed: false);
        await tester.pump();

        expect(wasTapped, isFalse);
      });

      testWidgets('applies loading className styling', (tester) async {
        await tester.pumpWidget(
          wrapWithTheme(
            WButton(
              onTap: () {},
              isLoading: true,
              className: 'bg-blue-500 loading:opacity-50',
              child: const Text('Submit'),
            ),
          ),
        );

        // Widget should render
        expect(find.byType(CircularProgressIndicator), findsOneWidget);
      });
    });

    group('Interaction Blocking', () {
      testWidgets('disabled button blocks interactions', (tester) async {
        bool wasTapped = false;

        await tester.pumpWidget(
          wrapWithTheme(
            WButton(
              onTap: () => wasTapped = true,
              disabled: true,
              child: const Text('Disabled'),
            ),
          ),
        );

        await tester.tap(find.text('Disabled'));
        await tester.pump();

        // onTap should not be called
        expect(wasTapped, isFalse);
      });

      testWidgets('loading button blocks interactions', (tester) async {
        bool wasTapped = false;

        await tester.pumpWidget(
          wrapWithTheme(
            WButton(
              onTap: () => wasTapped = true,
              isLoading: true,
              loadingText: 'Loading...',
              child: const Text('Submit'),
            ),
          ),
        );

        await tester.tap(find.text('Loading...'));
        await tester.pump();

        // onTap should not be called
        expect(wasTapped, isFalse);
      });
    });

    group('Hover State', () {
      testWidgets('hover state is applied on mouse enter', (tester) async {
        await tester.pumpWidget(
          wrapWithTheme(
            WButton(
              onTap: () {},
              className: 'bg-blue-500 hover:bg-red-500',
              child: const Text('Hover Me'),
            ),
          ),
        );

        // Find the MouseRegion (internal to WAnchor)
        final gesture = await tester.createGesture(
          kind: PointerDeviceKind.mouse,
        );
        await gesture.addPointer(location: Offset.zero);
        addTearDown(gesture.removePointer);

        // Move mouse over the button
        await gesture.moveTo(tester.getCenter(find.text('Hover Me')));
        await tester.pump();

        // Button should still render (hover styling applied)
        expect(find.text('Hover Me'), findsOneWidget);
      });

      testWidgets('hover state triggers rebuild with different style', (
        tester,
      ) async {
        await tester.pumpWidget(
          wrapWithTheme(
            WButton(
              onTap: () {},
              className: 'bg-blue-500 hover:bg-red-500 p-4 rounded-lg',
              child: const Text('Hover Me'),
            ),
          ),
        );

        // Get initial container
        final containerBefore = tester.widget<Container>(
          find.byType(Container).first,
        );
        final decorationBefore = containerBefore.decoration as BoxDecoration?;
        final colorBefore = decorationBefore?.color;

        // Simulate hover
        final gesture = await tester.createGesture(
          kind: PointerDeviceKind.mouse,
        );
        await gesture.addPointer(location: Offset.zero);
        addTearDown(gesture.removePointer);
        await gesture.moveTo(tester.getCenter(find.text('Hover Me')));
        await tester.pump(); // First pump processes hover event
        await tester.pump(); // Second pump processes postFrameCallback setState

        // Get container after hover
        final containerAfter = tester.widget<Container>(
          find.byType(Container).first,
        );
        final decorationAfter = containerAfter.decoration as BoxDecoration?;
        final colorAfter = decorationAfter?.color;

        // Colors should be different (blue -> red)
        expect(colorBefore, isNotNull);
        expect(colorAfter, isNotNull);
        expect(colorBefore, isNot(equals(colorAfter)));
      });
    });

    group('Custom States', () {
      testWidgets('custom states are applied via states parameter', (
        tester,
      ) async {
        await tester.pumpWidget(
          wrapWithTheme(
            WButton(
              onTap: () {},
              className: 'bg-blue-500 error:bg-red-500 p-4',
              states: {'error'},
              child: const Text('Error Button'),
            ),
          ),
        );

        // Get container
        final container = tester.widget<Container>(
          find.byType(Container).first,
        );
        final decoration = container.decoration as BoxDecoration?;

        // Color should be red (error state active)
        expect(decoration?.color, isNotNull);
        expect(find.text('Error Button'), findsOneWidget);
      });

      testWidgets('multiple custom states can be active', (tester) async {
        await tester.pumpWidget(
          wrapWithTheme(
            WButton(
              onTap: () {},
              className: 'bg-blue-500 error:bg-red-500 success:text-green-500',
              states: {'error', 'success'},
              child: const Text('Mixed States'),
            ),
          ),
        );

        expect(find.text('Mixed States'), findsOneWidget);
      });
    });

    group('Cursor Delegation', () {
      testWidgets('uses click cursor when interactive', (tester) async {
        await tester.pumpWidget(
          wrapWithTheme(
            WButton(onTap: () {}, child: const Text('Interactive')),
          ),
        );

        final mouseRegion = tester.widget<MouseRegion>(
          find
              .descendant(
                of: find.byType(WButton),
                matching: find.byType(MouseRegion),
              )
              .first,
        );
        expect(mouseRegion.cursor, equals(SystemMouseCursors.click));
      });

      testWidgets('uses forbidden cursor when disabled', (tester) async {
        await tester.pumpWidget(
          wrapWithTheme(
            WButton(
              onTap: () {},
              disabled: true,
              child: const Text('Disabled'),
            ),
          ),
        );

        final mouseRegion = tester.widget<MouseRegion>(
          find
              .descendant(
                of: find.byType(WButton),
                matching: find.byType(MouseRegion),
              )
              .first,
        );
        expect(mouseRegion.cursor, equals(SystemMouseCursors.forbidden));
      });

      testWidgets('uses forbidden cursor when loading', (tester) async {
        await tester.pumpWidget(
          wrapWithTheme(
            WButton(
              onTap: () {},
              isLoading: true,
              child: const Text('Loading'),
            ),
          ),
        );

        final mouseRegion = tester.widget<MouseRegion>(
          find
              .descendant(
                of: find.byType(WButton),
                matching: find.byType(MouseRegion),
              )
              .first,
        );
        expect(mouseRegion.cursor, equals(SystemMouseCursors.forbidden));
      });
    });

    group('onDoubleTap Callback', () {
      testWidgets('calls onDoubleTap when double tapped', (tester) async {
        bool wasDoubleTapped = false;

        await tester.pumpWidget(
          wrapWithTheme(
            WButton(
              onDoubleTap: () => wasDoubleTapped = true,
              child: const Text('Double Tap'),
            ),
          ),
        );

        await tester.tap(find.text('Double Tap'));
        await tester.pump(const Duration(milliseconds: 50));
        await tester.tap(find.text('Double Tap'));
        await tester.pumpAndSettle();

        expect(wasDoubleTapped, isTrue);
      });

      testWidgets('does not call onDoubleTap when disabled', (tester) async {
        bool wasDoubleTapped = false;

        await tester.pumpWidget(
          wrapWithTheme(
            WButton(
              onDoubleTap: () => wasDoubleTapped = true,
              disabled: true,
              child: const Text('Disabled'),
            ),
          ),
        );

        await tester.tap(find.text('Disabled'), warnIfMissed: false);
        await tester.pump(const Duration(milliseconds: 50));
        await tester.tap(find.text('Disabled'), warnIfMissed: false);
        await tester.pumpAndSettle();

        expect(wasDoubleTapped, isFalse);
      });

      testWidgets('does not call onDoubleTap when loading', (tester) async {
        bool wasDoubleTapped = false;

        await tester.pumpWidget(
          wrapWithTheme(
            WButton(
              onDoubleTap: () => wasDoubleTapped = true,
              isLoading: true,
              loadingText: 'Loading...',
              child: const Text('Submit'),
            ),
          ),
        );

        await tester.tap(find.text('Loading...'), warnIfMissed: false);
        await tester.pump(const Duration(milliseconds: 50));
        await tester.tap(find.text('Loading...'), warnIfMissed: false);
        // Use pump with fixed duration instead of pumpAndSettle
        // because CircularProgressIndicator animation never settles
        await tester.pump(const Duration(milliseconds: 500));

        expect(wasDoubleTapped, isFalse);
      });
    });

    group('Loading Spinner Color', () {
      testWidgets(
        'uses contrasting color on light background when no text color set',
        (tester) async {
          // BUG: White bg + no text color => spinner defaults to
          // Colors.white => invisible on white background.
          await tester.pumpWidget(
            wrapWithTheme(
              WButton(
                onTap: () {},
                isLoading: true,
                className: 'bg-white p-3 rounded-xl',
                child: const Text('Social Login'),
              ),
            ),
          );

          final indicator = tester.widget<CircularProgressIndicator>(
            find.byType(CircularProgressIndicator),
          );

          final animation =
              indicator.valueColor as AlwaysStoppedAnimation<Color>;
          final spinnerColor = animation.value;

          // Spinner should NOT be white on a white background.
          expect(
            spinnerColor,
            isNot(equals(Colors.white)),
            reason:
                'Loading spinner should use a contrasting color, not white on white bg',
          );
        },
      );

      testWidgets(
        'uses contrasting color on dark background when no text color set',
        (tester) async {
          await tester.pumpWidget(
            wrapWithTheme(
              WButton(
                onTap: () {},
                isLoading: true,
                className: 'bg-gray-900 p-3 rounded-xl',
                child: const Text('Dark Button'),
              ),
            ),
          );

          final indicator = tester.widget<CircularProgressIndicator>(
            find.byType(CircularProgressIndicator),
          );

          final animation =
              indicator.valueColor as AlwaysStoppedAnimation<Color>;
          final spinnerColor = animation.value;

          // On dark background, spinner should be light (white is fine).
          expect(
            spinnerColor,
            equals(Colors.white),
            reason: 'Loading spinner should be white on dark background',
          );
        },
      );

      testWidgets(
        'uses explicit text color from className for spinner',
        (tester) async {
          await tester.pumpWidget(
            wrapWithTheme(
              WButton(
                onTap: () {},
                isLoading: true,
                className: 'bg-white text-blue-600 p-3 rounded-xl',
                child: const Text('Styled Button'),
              ),
            ),
          );

          final indicator = tester.widget<CircularProgressIndicator>(
            find.byType(CircularProgressIndicator),
          );

          final animation =
              indicator.valueColor as AlwaysStoppedAnimation<Color>;
          final spinnerColor = animation.value;

          // When text color is set, spinner should use it.
          expect(
            spinnerColor,
            isNot(equals(Colors.white)),
            reason:
                'Loading spinner should use the explicit text color from className',
          );
        },
      );

      testWidgets(
        'uses explicit loadingColor over all fallbacks',
        (tester) async {
          await tester.pumpWidget(
            wrapWithTheme(
              WButton(
                onTap: () {},
                isLoading: true,
                loadingColor: Colors.red,
                className: 'bg-white p-3 rounded-xl',
                child: const Text('Custom Color'),
              ),
            ),
          );

          final indicator = tester.widget<CircularProgressIndicator>(
            find.byType(CircularProgressIndicator),
          );

          final animation =
              indicator.valueColor as AlwaysStoppedAnimation<Color>;
          final spinnerColor = animation.value;

          // Explicit loadingColor should take precedence.
          expect(spinnerColor, equals(Colors.red));
        },
      );
    });
  });
}
