import 'package:block_seasons/data/save_repository.dart';
import 'package:block_seasons/game/engine/game_engine.dart';
import 'package:block_seasons/game/models/season.dart';
import 'package:block_seasons/l10n/gen/app_localizations.dart';
import 'package:block_seasons/state/providers.dart';
import 'package:block_seasons/ui/screens/game_screen.dart';
import 'package:block_seasons/ui/screens/season_map_screen.dart';
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:shared_preferences/shared_preferences.dart';

// The real 60-stage bundled pack is covered by the content repository
// tests; the widget test uses a small pack because the bundled one is big
// enough that loadString decodes on an isolate, which fake-async test time
// never completes.
SeasonPack _pack() => SeasonPack.fromJson({
      'schemaVersion': 1,
      'seasonId': 'season_001',
      'version': 1,
      'title': {'en': 'First Bloom', 'ko': '첫 개화'},
      'theme': {'tileSet': 'spring', 'background': 'bg.webp'},
      'stages': [
        for (var i = 1; i <= 3; i++)
          {
            'id': 'season_001_00$i',
            'seed': 100 + i,
            'moveLimit': 20,
            'preset': const <Map<String, dynamic>>[],
            'objectives': [
              {'type': 'reachScore', 'target': 999999},
            ],
            'stars': {
              'two': {'movesLeft': 5},
              'three': {'movesLeft': 10},
            },
            'generatorProfile': 'mid',
          },
      ],
    });

void main() {
  testWidgets('map shows stars, locks ahead, and starts unlocked stages',
      (tester) async {
    SharedPreferences.setMockInitialValues({});
    final repo = SaveRepository(await SharedPreferences.getInstance());
    await repo.recordResult(
      seasonId: 'season_001',
      stageId: 'season_001_001',
      stars: 2,
      score: 300,
    );

    final container = ProviderContainer(
      overrides: [
        saveRepositoryProvider.overrideWithValue(repo),
        seasonsProvider.overrideWith((ref) async => [_pack()]),
      ],
    );
    addTearDown(container.dispose);

    await tester.pumpWidget(
      UncontrolledProviderScope(
        container: container,
        child: const MaterialApp(
          localizationsDelegates: AppLocalizations.localizationsDelegates,
          supportedLocales: AppLocalizations.supportedLocales,
          home: SeasonMapScreen(),
        ),
      ),
    );
    await tester.pumpAndSettle();

    // Total stars displayed in header.
    expect(find.text('★ 2/9'), findsOneWidget);

    // Node 0 (stage 1) exists.
    expect(find.byKey(const Key('stage_node_0')), findsOneWidget);

    // Stage 3 (index 2) is locked — contains a lock icon.
    expect(
      find.descendant(
        of: find.byKey(const Key('stage_node_2')),
        matching: find.byIcon(Icons.lock),
      ),
      findsOneWidget,
    );

    // Stage 1 is starred, so stage 2 (index 1) is unlocked and playable.
    // Ensure the node is visible before tapping.
    await tester.ensureVisible(find.byKey(const Key('stage_node_1')));
    await tester.tap(find.byKey(const Key('stage_node_1')));
    await tester.pumpAndSettle();

    expect(find.byType(GameScreen), findsOneWidget);
    final session = container.read(gameSessionProvider);
    expect(session, isNotNull);
    expect(session!.phase, GamePhase.playing);
    expect(container.read(seasonFlowProvider)!.stage.id, 'season_001_002');
  });
}
