// SPDX-FileCopyrightText: 2026 FocusFlow contributors
// SPDX-License-Identifier: AGPL-3.0-only

/// Tests Forbidden Imports behavior in the FocusFlow Flutter app.
library;

import 'dart:io';

import 'package:flutter_test/flutter_test.dart';

/// Runs app package-boundary tests.
void main() {
  test(
    'Flutter UI imports stay inside the SQLite runtime package boundary',
    () {
      final appRoot = Directory.current;
      final dartFiles = <File>[
        ..._dartFiles(Directory('${appRoot.path}/lib')),
        ..._dartFiles(Directory('${appRoot.path}/test')),
      ];

      final violations = <String>[];
      for (final file in dartFiles) {
        final relativePath = file.path.substring(appRoot.path.length + 1);
        final contents = file.readAsStringSync();
        for (final forbidden in _forbiddenImportsFor(relativePath)) {
          if (forbidden.matches(contents)) {
            violations.add('$relativePath imports ${forbidden.label}');
          }
        }
      }

      expect(
        violations,
        isEmpty,
        reason: 'Forbidden imports found:\n${violations.join('\n')}',
      );
    },
  );
}

/// Top-level helper that performs the `_dartFiles` operation for this file.
/// Keeping the helper private makes the surrounding flow easier to read while preventing unrelated libraries from depending on implementation detail.
Iterable<File> _dartFiles(Directory directory) {
  if (!directory.existsSync()) {
    return const <File>[];
  }
  return directory
      .listSync(recursive: true)
      .whereType<File>()
      .where((file) => file.path.endsWith('.dart'));
}

/// Top-level helper that performs the `_forbiddenImportsFor` operation for this file.
/// Keeping the helper private makes the surrounding flow easier to read while preventing unrelated libraries from depending on implementation detail.
List<_ForbiddenImport> _forbiddenImportsFor(String relativePath) {
  return [
    const _ForbiddenImport(
      "package:scheduler_core/src/",
      'scheduler_core internals',
    ),
    if (!_isPersistentComposition(relativePath))
      const _ForbiddenImport(
        "package:scheduler_persistence_sqlite/",
        'SQLite persistence adapter',
      ),
    const _ForbiddenImport("package:drift/", 'Drift'),
    const _ForbiddenImport(
      "package:scheduler_notifications_desktop/",
      'desktop notification implementation',
    ),
    const _ForbiddenImport("package:scheduler_backup/", 'backup package'),
    const _ForbiddenImport("package:scheduler_export/", 'export package'),
    const _ForbiddenImport(
      "package:scheduler_export_json/",
      'JSON export package',
    ),
    if (relativePath != 'test/forbidden_imports_test.dart' &&
        relativePath != 'test/persistent_composition_test.dart' &&
        relativePath != 'test/app/runtime_config_test.dart' &&
        !_isApprovedRuntimeBoundary(relativePath))
      const _ForbiddenImport("dart:io", 'dart:io'),
  ];
}

/// Whether [relativePath] is the approved persistent runtime composition root.
bool _isPersistentComposition(String relativePath) {
  return relativePath == 'lib/app/persistent_scheduler_composition.dart';
}

/// Whether [relativePath] is approved to touch local runtime files directly.
bool _isApprovedRuntimeBoundary(String relativePath) {
  return _isPersistentComposition(relativePath) ||
      relativePath.startsWith('lib/app/runtime/');
}

/// Private implementation type for `_ForbiddenImport` in this library.
/// It keeps supporting state and behavior scoped to the owning file so the public API stays focused on the scheduler concepts that callers use directly.
class _ForbiddenImport {
  /// Creates a `_ForbiddenImport` instance with the values required by its invariants.
  /// Callers should pass already-normalized scheduler data because validation and defaulting belong at the model or service boundary, not in arbitrary UI code.
  const _ForbiddenImport(this.pattern, this.label);

  /// Stores the `pattern` value for this object.
  /// This field is part of the explicit state that downstream scheduling, persistence, or UI code reads when composing behavior.
  final String pattern;

  /// Stores the `label` value for this object.
  /// This field is part of the explicit state that downstream scheduling, persistence, or UI code reads when composing behavior.
  final String label;

  /// Performs the `matches` behavior for this scheduler component.
  /// The method provides a named entry point for this operation so callers do not need to know the lower-level state or persistence steps involved.
  bool matches(String contents) {
    return RegExp(
      r'''import\s+['"]''' + RegExp.escape(pattern),
    ).hasMatch(contents);
  }
}
