// Copyright 2013 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

import 'package:test/test.dart';

import 'package:ui/src/engine.dart';
import 'package:ui/ui.dart' as ui;

/// Whether the current browser is Safari on iOS.
// TODO: https://github.com/flutter/flutter/issues/60040
bool get isIosSafari =>
    browserEngine == BrowserEngine.webkit &&
    operatingSystem == OperatingSystem.iOs;

/// Whether the current browser is Firefox.
bool get isFirefox => browserEngine == BrowserEngine.firefox;

/// Used in tests instead of [ProductionCollector] to control Skia object
/// collection explicitly, and to prevent leaks across tests.
///
/// See [TestCollector] for usage.
late TestCollector testCollector;

/// Common test setup for all CanvasKit unit-tests.
void setUpCanvasKitTest() {
  setUpAll(() async {
    expect(useCanvasKit, true, reason: 'This test must run in CanvasKit mode.');
    debugResetBrowserSupportsFinalizationRegistry();
    await ui.webOnlyInitializePlatform(assetManager: WebOnlyMockAssetManager());
  });

  setUp(() async {
    testCollector = TestCollector();
    Collector.debugOverrideCollector(testCollector);
  });

  tearDown(() {
    testCollector.cleanUpAfterTest();
    debugResetBrowserSupportsFinalizationRegistry();
    OverlayCache.instance.debugClear();
  });

  tearDownAll(() {
    debugResetBrowserSupportsFinalizationRegistry();
  });
}

/// Utility function for CanvasKit tests to draw pictures without
/// the [CkPictureRecorder] boilerplate.
CkPicture paintPicture(
    ui.Rect cullRect, void Function(CkCanvas canvas) painter) {
  final CkPictureRecorder recorder = CkPictureRecorder();
  final CkCanvas canvas = recorder.beginRecording(cullRect);
  painter(canvas);
  return recorder.endRecording();
}

class _TestFinalizerRegistration {
  _TestFinalizerRegistration(this.wrapper, this.deletable, this.stackTrace);

  final Object wrapper;
  final SkDeletable deletable;
  final StackTrace stackTrace;
}

class _TestCollection {
  _TestCollection(this.deletable, this.stackTrace);

  final SkDeletable deletable;
  final StackTrace stackTrace;
}

/// Provides explicit synchronous API for collecting Skia objects in tests.
///
/// [ProductionCollector] relies on `FinalizationRegistry` and timers to
/// delete Skia objects, which makes it more precise and efficient. However,
/// it also makes it unpredictable. For example, an object created in one
/// test may be collected while running another test because the timing is
/// subject to browser-specific GC scheduling.
///
/// Tests should use [collectNow] and [collectAfterTest] to trigger collections.
class TestCollector implements Collector {
  final List<_TestFinalizerRegistration> _activeRegistrations =
      <_TestFinalizerRegistration>[];
  final List<_TestFinalizerRegistration> _collectedRegistrations =
      <_TestFinalizerRegistration>[];

  final List<_TestCollection> _pendingCollections = <_TestCollection>[];
  final List<_TestCollection> _completedCollections = <_TestCollection>[];

  @override
  void register(Object wrapper, SkDeletable deletable) {
    _activeRegistrations.add(
      _TestFinalizerRegistration(wrapper, deletable, StackTrace.current),
    );
  }

  @override
  void collect(SkDeletable deletable) {
    _pendingCollections.add(
      _TestCollection(deletable, StackTrace.current),
    );
  }

  /// Deletes all Skia objects scheduled for collection.
  void collectNow() {
    for (_TestCollection collection in _pendingCollections) {
      late final _TestFinalizerRegistration? activeRegistration;
      for (_TestFinalizerRegistration registration in _activeRegistrations) {
        if (identical(registration.deletable, collection.deletable)) {
          activeRegistration = registration;
          break;
        }
      }
      if (activeRegistration == null) {
        late final _TestFinalizerRegistration? collectedRegistration;
        for (_TestFinalizerRegistration registration
            in _collectedRegistrations) {
          if (identical(registration.deletable, collection.deletable)) {
            collectedRegistration = registration;
            break;
          }
        }
        if (collectedRegistration == null) {
          fail(
              'Attempted to collect an object that was never registered for finalization.\n'
              'The collection was requested here:\n'
              '${collection.stackTrace}');
        } else {
          final _TestCollection firstCollection = _completedCollections
              .firstWhere((_TestCollection completedCollection) {
            return identical(
                completedCollection.deletable, collection.deletable);
          });
          fail(
            'Attempted to collect an object that was previously collected.\n'
            'The object was registered for finalization here:\n'
            '${collection.stackTrace}\n\n'
            'The first collection was requested here:\n'
            '${firstCollection.stackTrace}\n\n'
            'The second collection was requested here:\n'
            '${collection.stackTrace}',
          );
        }
      } else {
        _collectedRegistrations.add(activeRegistration);
        _activeRegistrations.remove(activeRegistration);
        _completedCollections.add(collection);
        if (!collection.deletable.isDeleted()) {
          collection.deletable.delete();
        }
      }
    }
    _pendingCollections.clear();
  }

  /// Deletes all Skia objects with registered finalizers.
  ///
  /// This also deletes active objects that have not been scheduled for
  /// collection, to prevent objects leaking across tests.
  void cleanUpAfterTest() {
    for (_TestCollection collection in _pendingCollections) {
      if (!collection.deletable.isDeleted()) {
        collection.deletable.delete();
      }
    }
    for (_TestFinalizerRegistration registration in _activeRegistrations) {
      if (!registration.deletable.isDeleted()) {
        registration.deletable.delete();
      }
    }
    _activeRegistrations.clear();
    _collectedRegistrations.clear();
    _pendingCollections.clear();
    _completedCollections.clear();
  }
}
