// Widget test of the INTEGRATED live drawing path (device-independent: uses a
// plain Container as the page widget, so no pdfrx/pdfium). Exercises the input
// arbiter + stroke lifecycle + the revision-gated render-cache swap (eca5141)
// end-to-end via simulated stylus / finger / pinch gestures.

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

import 'package:badnote/editor/canvas/pen_canvas.dart';
import 'package:badnote/editor/canvas/pen_stroke.dart';

void main() {
  const pageSize = Size(400, 600);

  Widget host({
    required List<PenStroke> strokes,
    required void Function(PenStroke) onComplete,
    required TransformationController controller,
    bool allowFinger = false,
    CanvasTool tool = CanvasTool.pen,
  }) {
    return MaterialApp(
      home: Scaffold(
        body: Center(
          child: SizedBox(
            width: pageSize.width,
            height: pageSize.height,
            child: PenCanvas(
              pageWidget: Container(color: const Color(0xFFEEEEEE)),
              pageSize: pageSize,
              strokes: strokes,
              transformationController: controller,
              tool: tool,
              color: const Color(0xFF000000),
              strokeWidth: 0.004,
              allowFingerDrawing: allowFinger,
              onStrokeComplete: onComplete,
              onEraseStroke: (_, _) {},
            ),
          ),
        ),
      ),
    );
  }

  testWidgets('a stylus drag produces a committed stroke', (tester) async {
    final committed = <PenStroke>[];
    final controller = TransformationController();
    addTearDown(controller.dispose);

    await tester.pumpWidget(host(
      strokes: const [],
      onComplete: committed.add,
      controller: controller,
    ));

    final center = tester.getCenter(find.byType(PenCanvas));
    final g = await tester.startGesture(center,
        kind: PointerDeviceKind.stylus);
    await g.moveBy(const Offset(20, 10));
    await g.moveBy(const Offset(20, 30));
    await g.moveBy(const Offset(10, 20));
    await g.up();
    await tester.pump();

    expect(committed, hasLength(1));
    expect(committed.single.points.length, greaterThan(1),
        reason: 'a multi-segment drag is not a single dot');
  });

  testWidgets('a single finger does NOT draw when finger-drawing is off',
      (tester) async {
    final committed = <PenStroke>[];
    final controller = TransformationController();
    addTearDown(controller.dispose);

    await tester.pumpWidget(host(
      strokes: const [],
      onComplete: committed.add,
      controller: controller,
      allowFinger: false,
    ));

    final center = tester.getCenter(find.byType(PenCanvas));
    final g = await tester.startGesture(center, kind: PointerDeviceKind.touch);
    await g.moveBy(const Offset(30, 30));
    await g.up();
    await tester.pump();

    expect(committed, isEmpty, reason: 'palm/finger rejection');
  });

  testWidgets('a finger DOES draw when finger-drawing is on', (tester) async {
    final committed = <PenStroke>[];
    final controller = TransformationController();
    addTearDown(controller.dispose);

    await tester.pumpWidget(host(
      strokes: const [],
      onComplete: committed.add,
      controller: controller,
      allowFinger: true,
    ));

    final center = tester.getCenter(find.byType(PenCanvas));
    final g = await tester.startGesture(center, kind: PointerDeviceKind.touch);
    await g.moveBy(const Offset(30, 30));
    await g.up();
    await tester.pump();

    expect(committed, hasLength(1));
  });

  testWidgets('a second pointer cancels an in-progress stylus stroke (pinch)',
      (tester) async {
    final committed = <PenStroke>[];
    final controller = TransformationController();
    addTearDown(controller.dispose);

    await tester.pumpWidget(host(
      strokes: const [],
      onComplete: committed.add,
      controller: controller,
    ));

    final center = tester.getCenter(find.byType(PenCanvas));
    final g1 = await tester.startGesture(center, kind: PointerDeviceKind.stylus);
    await g1.moveBy(const Offset(10, 10));
    // A second finger lands → the stroke must be discarded (pinch/palm).
    final g2 = await tester.startGesture(
        center + const Offset(60, 0), kind: PointerDeviceKind.touch);
    await g1.moveBy(const Offset(10, 10));
    await g1.up();
    await g2.up();
    await tester.pump();

    expect(committed, isEmpty, reason: '2nd pointer cancels the stroke');
  });

  testWidgets('renders committed strokes through the render cache without error',
      (tester) async {
    final controller = TransformationController();
    addTearDown(controller.dispose);
    final strokes = [
      PenStroke(
        points: const [PenPoint(0.1, 0.1, 0.5), PenPoint(0.4, 0.5, 0.6)],
        color: 0xFF000000,
        width: 0.004,
        kind: PenStrokeKind.pen,
      ),
    ];

    await tester.pumpWidget(host(
      strokes: strokes,
      onComplete: (_) {},
      controller: controller,
    ));
    await tester.pump();

    // Built + painted the StaticInkPainter (render cache) with no exception.
    expect(tester.takeException(), isNull);
    expect(find.byType(PenCanvas), findsOneWidget);
  });
}
