import 'package:flutter_test/flutter_test.dart';
import 'package:plezy/media/media_backend.dart';
import 'package:plezy/media/media_kind.dart';
import 'package:plezy/media/media_library.dart';
import 'package:plezy/providers/libraries_provider.dart';
import 'package:plezy/services/storage_service.dart';

import '../test_helpers/prefs.dart';

MediaLibrary _lib(String key, {String type = 'movie', String? serverId, String title = 'L'}) => MediaLibrary(
  id: key,
  backend: MediaBackend.plex,
  title: title,
  kind: MediaKind.fromString(type),
  serverId: serverId,
);

void main() {
  setUp(resetSharedPreferencesForTest);

  group('LibrariesProvider', () {
    test('starts with initial empty state', () {
      final p = LibrariesProvider();
      expect(p.libraries, isEmpty);
      expect(p.hasLibraries, isFalse);
      expect(p.isLoading, isFalse);
      expect(p.hasLoaded, isFalse);
      expect(p.loadState, LibrariesLoadState.initial);
      expect(p.errorMessage, isNull);
      p.dispose();
    });

    test('loadLibraries before initialize is a no-op', () async {
      final p = LibrariesProvider();
      var notified = 0;
      p.addListener(() => notified++);

      await p.loadLibraries();

      // Without a DataAggregationService the load short-circuits with no
      // state transition and no listener notification.
      expect(p.loadState, LibrariesLoadState.initial);
      expect(p.libraries, isEmpty);
      expect(notified, 0);

      p.dispose();
    });

    test('refresh before initialize is a no-op', () async {
      final p = LibrariesProvider();
      var notified = 0;
      p.addListener(() => notified++);

      await p.refresh();
      expect(p.loadState, LibrariesLoadState.initial);
      expect(notified, 0);

      p.dispose();
    });

    test('updateLibraryOrder updates list, notifies, and persists order', () async {
      final p = LibrariesProvider();
      var notified = 0;
      p.addListener(() => notified++);

      final libs = [
        _lib('1', serverId: 'srv', title: 'A'),
        _lib('2', serverId: 'srv', title: 'B'),
        _lib('3', serverId: 'srv', title: 'C'),
      ];

      await p.updateLibraryOrder(libs);
      expect(p.libraries.length, 3);
      expect(p.libraries.map((l) => l.title), ['A', 'B', 'C']);
      expect(notified, 1);

      // Persisted to storage as the list of globalKeys.
      final storage = await StorageService.getInstance();
      expect(storage.getLibraryOrder(), equals(libs.map((l) => l.globalKey).toList()));

      p.dispose();
    });

    test('libraries getter returns an unmodifiable list', () async {
      final p = LibrariesProvider();
      await p.updateLibraryOrder([_lib('1', serverId: 'srv')]);
      expect(() => p.libraries.add(_lib('mutated')), throwsUnsupportedError);
      p.dispose();
    });

    test('clear resets state to initial and notifies', () async {
      final p = LibrariesProvider();
      await p.updateLibraryOrder([_lib('1', serverId: 'srv'), _lib('2', serverId: 'srv')]);
      expect(p.libraries, hasLength(2));

      var notified = 0;
      p.addListener(() => notified++);

      p.clear();
      expect(p.libraries, isEmpty);
      expect(p.hasLibraries, isFalse);
      expect(p.loadState, LibrariesLoadState.initial);
      expect(p.errorMessage, isNull);
      expect(notified, 1);

      p.dispose();
    });

    test('safeNotifyListeners after dispose is a no-op', () async {
      final p = LibrariesProvider();
      p.dispose();
      // Post-dispose clear / updateLibraryOrder must not throw — the provider
      // uses `safeNotifyListeners` which swallows post-dispose firings.
      p.clear();
      await p.updateLibraryOrder([_lib('1', serverId: 'srv')]);
    });
  });
}
