// 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();
  }
}
