import 'package:flutter/gestures.dart';
import 'package:flutter/material.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:marianum_mobile/widget/prosemirror/pm_document_view.dart';
import 'package:marianum_mobile/widget/prosemirror/pm_node.dart';

const _pngDataUri =
    'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAAC0lEQVR4nGP4DwQACfsD/fteaysAAAAASUVORK5CYII=';

Map<String, dynamic> _kitchenSinkDoc() => {
  'type': 'doc',
  'content': [
    {
      'type': 'heading',
      'attrs': {'level': 1},
      'content': [
        {'type': 'text', 'text': 'Heading'},
      ],
    },
    {
      'type': 'paragraph',
      'content': [
        {
          'type': 'text',
          'text': 'bold ',
          'marks': [
            {'type': 'bold'},
          ],
        },
        {
          'type': 'text',
          'text': 'link',
          'marks': [
            {
              'type': 'link',
              'attrs': {'href': 'https://example.org'},
            },
          ],
        },
        {'type': 'hardBreak'},
        {
          'type': 'text',
          'text': 'code',
          'marks': [
            {'type': 'code'},
          ],
        },
      ],
    },
    {
      'type': 'bulletList',
      'content': [
        {
          'type': 'listItem',
          'content': [
            {
              'type': 'paragraph',
              'content': [
                {'type': 'text', 'text': 'item'},
              ],
            },
          ],
        },
      ],
    },
    {
      'type': 'callout',
      'attrs': {'variant': 'info'},
      'content': [
        {
          'type': 'paragraph',
          'content': [
            {'type': 'text', 'text': 'note'},
          ],
        },
      ],
    },
    {
      'type': 'codeBlock',
      'content': [
        {'type': 'text', 'text': 'x = 1'},
      ],
    },
    {'type': 'horizontalRule'},
    {
      'type': 'image',
      'attrs': {'src': _pngDataUri, 'align': 'center', 'width': '40%'},
    },
    {
      'type': 'unknownWidget',
      'content': [
        {
          'type': 'paragraph',
          'content': [
            {'type': 'text', 'text': 'fallback child'},
          ],
        },
      ],
    },
    {
      'type': 'table',
      'content': [
        {
          'type': 'tableRow',
          'content': [
            {
              'type': 'tableHeader',
              'attrs': {'colspan': 2},
              'content': [
                {
                  'type': 'paragraph',
                  'content': [
                    {'type': 'text', 'text': 'head'},
                  ],
                },
              ],
            },
          ],
        },
        {
          'type': 'tableRow',
          'content': [
            {
              'type': 'tableCell',
              'content': [
                {
                  'type': 'paragraph',
                  'content': [
                    {'type': 'text', 'text': 'a'},
                  ],
                },
              ],
            },
            {
              'type': 'tableCell',
              'content': [
                {
                  'type': 'paragraph',
                  'content': [
                    {'type': 'text', 'text': 'b'},
                  ],
                },
              ],
            },
          ],
        },
      ],
    },
  ],
};

Widget _host(Brightness brightness, {void Function(String href)? onLinkTap}) {
  return MaterialApp(
    theme: ThemeData(
      colorScheme: ColorScheme.fromSeed(
        seedColor: const Color(0xFF993333),
        brightness: brightness,
      ),
    ),
    home: Scaffold(
      body: SingleChildScrollView(
        child: PmDocumentView(
          doc: PmNode.fromJson(_kitchenSinkDoc()),
          onLinkTap: onLinkTap,
        ),
      ),
    ),
  );
}

void main() {
  testWidgets('renders kitchen-sink doc in light theme without exception', (
    tester,
  ) async {
    await tester.pumpWidget(_host(Brightness.light));
    await tester.pump();

    expect(tester.takeException(), isNull);
    expect(find.text('Heading'), findsOneWidget);
    expect(find.text('note'), findsOneWidget);
    expect(find.text('fallback child'), findsOneWidget);
  });

  testWidgets('renders kitchen-sink doc in dark theme without exception', (
    tester,
  ) async {
    await tester.pumpWidget(_host(Brightness.dark));
    await tester.pump();

    expect(tester.takeException(), isNull);
    expect(find.text('Heading'), findsOneWidget);
  });

  testWidgets('link marks route through onLinkTap', (tester) async {
    final tapped = <String>[];
    await tester.pumpWidget(_host(Brightness.light, onLinkTap: tapped.add));
    await tester.pump();

    final richTexts = tester.widgetList<RichText>(find.byType(RichText));
    for (final richText in richTexts) {
      if (TapGestureRecognizerHarness.tapFirstLink(richText.text)) break;
    }

    expect(tapped, ['https://example.org']);
  });
}

/// Walks a composed span tree and fires the first link recognizer it finds,
/// returning whether one was tapped.
class TapGestureRecognizerHarness {
  static bool tapFirstLink(InlineSpan span) {
    var tapped = false;
    span.visitChildren((child) {
      if (child is TextSpan) {
        final recognizer = child.recognizer;
        if (recognizer is TapGestureRecognizer && recognizer.onTap != null) {
          recognizer.onTap!();
          tapped = true;
          return false;
        }
      }
      return true;
    });
    return tapped;
  }
}
