import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:shared_preferences/shared_preferences.dart';
import 'package:smplayer/core/domain/ports/sm_account_gateway.dart';
import 'package:smplayer/providers/sm_account_provider.dart';
import 'package:smplayer/providers/tmdb_settings_provider.dart';

void main() {
  TestWidgetsFlutterBinding.ensureInitialized();

  const tmdbEnabledKey = 'smplayer.tmdb_enabled';
  const tmdbAccessModeKey = 'smplayer.tmdb_access_mode';
  const tmdbApiKeyKey = 'smplayer.tmdb_api_key';
  const tmdbLanguageKey = 'smplayer.tmdb_language';

  ProviderContainer makeContainer(SmLoginResult loginResult) {
    final c = ProviderContainer(
      overrides: [
        smAccountGatewayProvider.overrideWithValue(
          _FakeSmAccountGateway(loginResult),
        ),
      ],
    );
    addTearDown(c.dispose);
    return c;
  }

  test('VIP login enables TMDB through sm-server proxy', () async {
    SharedPreferences.setMockInitialValues({
      tmdbEnabledKey: false,
      tmdbAccessModeKey: TmdbAccessMode.official.name,
      tmdbApiKeyKey: 'keep-me',
      tmdbLanguageKey: 'en-US',
    });
    final c = makeContainer(
      const SmLoginResult(
        ok: true,
        email: 'vip@example.com',
        accessToken: 'access',
        refreshToken: 'refresh',
        expiresIn: 900,
        isVip: true,
      ),
    );

    await c.read(smAccountProvider.future);
    final result = await c
        .read(smAccountProvider.notifier)
        .login('vip@example.com', 'password');

    expect(result.ok, isTrue);
    final settings = await c.read(tmdbSettingsProvider.future);
    expect(settings.enabled, isTrue);
    expect(settings.accessMode, TmdbAccessMode.smAccount);
    expect(settings.apiKey, 'keep-me');
    expect(settings.language, 'en-US');

    final prefs = await SharedPreferences.getInstance();
    expect(prefs.getBool(tmdbEnabledKey), isTrue);
    expect(prefs.getString(tmdbAccessModeKey), TmdbAccessMode.smAccount.name);
  });

  test('non-VIP login leaves TMDB settings unchanged', () async {
    SharedPreferences.setMockInitialValues({
      tmdbEnabledKey: false,
      tmdbAccessModeKey: TmdbAccessMode.official.name,
    });
    final c = makeContainer(
      const SmLoginResult(
        ok: true,
        email: 'user@example.com',
        accessToken: 'access',
        refreshToken: 'refresh',
        expiresIn: 900,
      ),
    );

    await c.read(smAccountProvider.future);
    final result = await c
        .read(smAccountProvider.notifier)
        .login('user@example.com', 'password');

    expect(result.ok, isTrue);
    final settings = await c.read(tmdbSettingsProvider.future);
    expect(settings.enabled, isFalse);
    expect(settings.accessMode, TmdbAccessMode.official);

    final prefs = await SharedPreferences.getInstance();
    expect(prefs.getBool(tmdbEnabledKey), isFalse);
    expect(prefs.getString(tmdbAccessModeKey), TmdbAccessMode.official.name);
  });
}

class _FakeSmAccountGateway implements SmAccountGateway {
  final SmLoginResult loginResult;

  _FakeSmAccountGateway(this.loginResult);

  @override
  Future<SmLoginResult> login({
    required String baseUrl,
    required String email,
    required String password,
  }) async => loginResult;

  @override
  Future<void> logout({
    required String baseUrl,
    required String refreshToken,
  }) async {}

  @override
  Future<SmTokenRefreshResult> refreshAccessToken({
    required String baseUrl,
    required String refreshToken,
  }) async => const SmTokenRefreshResult(ok: false);

  @override
  Future<SmActionResult> registerStart({
    required String baseUrl,
    required String email,
  }) async => SmActionResult.failure('unused');

  @override
  Future<SmLoginResult> registerVerify({
    required String baseUrl,
    required String email,
    required String password,
    required String code,
  }) async => loginResult;

  @override
  Future<SmActionResult> resendCode({
    required String baseUrl,
    required String email,
  }) async => SmActionResult.failure('unused');
}
