import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';

import '../../game/models/season.dart';
import '../../state/providers.dart';
import '../theme/palette.dart';
import '../widgets/banner_ad_slot.dart';
import '../widgets/fade_route.dart';
import '../widgets/map_layout.dart';
import '../widgets/pressable_scale.dart';
import '../widgets/season_background.dart';
import '../widgets/tile_painter.dart';
import 'game_screen.dart';

/// Journey map: a serpentine path of stage nodes climbing the season
/// illustration. Auto-scrolls to the current stage on entry.
class SeasonMapScreen extends ConsumerWidget {
  const SeasonMapScreen({super.key});

  @override
  Widget build(BuildContext context, WidgetRef ref) {
    final seasons = ref.watch(seasonsProvider);
    return seasons.when(
      loading: () =>
          const Scaffold(body: Center(child: CircularProgressIndicator())),
      error: (e, _) => Scaffold(body: Center(child: Text('$e'))),
      data: (list) => list.isEmpty
          ? const Scaffold(body: Center(child: CircularProgressIndicator()))
          : _JourneyMap(pack: activeSeason(list)),
    );
  }
}

class _JourneyMap extends ConsumerStatefulWidget {
  const _JourneyMap({required this.pack});

  final SeasonPack pack;

  @override
  ConsumerState<_JourneyMap> createState() => _JourneyMapState();
}

class _JourneyMapState extends ConsumerState<_JourneyMap> {
  final _scroll = ScrollController();
  bool _autoScrolled = false;

  @override
  void dispose() {
    _scroll.dispose();
    super.dispose();
  }

  void _autoScrollTo(
      MapLayout layout, int current, int count, double viewportHeight) {
    if (_autoScrolled || !_scroll.hasClients) return;
    _autoScrolled = true;
    final contentH = layout.heightFor(count);
    final target =
        (contentH - layout.nodeCenter(current, count).dy - viewportHeight / 2)
            .clamp(0.0, _scroll.position.maxScrollExtent);
    _scroll.jumpTo(target);
  }

  @override
  Widget build(BuildContext context) {
    // Watching progress keeps stars/locks fresh after each win.
    ref.watch(progressProvider);
    final pack = widget.pack;
    final repo = ref.read(saveRepositoryProvider);
    final ids = [for (final stage in pack.stages) stage.id];
    final unlocked = repo.highestUnlockedIndex(pack.seasonId, ids);
    final totalStars = repo.totalStars(pack.seasonId);
    final seasonComplete = totalStars == pack.stages.length * 3 &&
        pack.stages.isNotEmpty;
    final locale = Localizations.localeOf(context).languageCode;
    final colors = ThemeColors(pack.theme);

    return Scaffold(
      backgroundColor: Colors.transparent,
      body: SafeArea(
        child: Column(
          children: [
            Expanded(
              child: Stack(
                fit: StackFit.expand,
                children: [
                  SeasonBackground(theme: pack.theme),
                  LayoutBuilder(
                    builder: (context, constraints) {
                      final layout = MapLayout(width: constraints.maxWidth);
                      final count = pack.stages.length;
                      if (!_autoScrolled) {
                        WidgetsBinding.instance.addPostFrameCallback((_) =>
                            _autoScrollTo(
                                layout, unlocked, count, constraints.maxHeight));
                      }
                      return SingleChildScrollView(
                        controller: _scroll,
                        reverse: true,
                        child: SizedBox(
                          width: constraints.maxWidth,
                          height: layout.heightFor(count),
                          child: Stack(
                            children: [
                              CustomPaint(
                                size: Size(
                                    constraints.maxWidth, layout.heightFor(count)),
                                painter:
                                    _PathPainter(layout: layout, count: count),
                              ),
                              for (var i = 0; i < count; i++)
                                _node(
                                  context,
                                  layout,
                                  i,
                                  count,
                                  unlocked,
                                  repo.progressFor(pack.seasonId, ids[i])?.stars ?? 0,
                                  colors,
                                  seasonComplete,
                                ),
                            ],
                          ),
                        ),
                      );
                    },
                  ),
                  // Glass header.
                  Positioned(
                    top: 0,
                    left: 0,
                    right: 0,
                    child: Container(
                      padding: const EdgeInsets.only(
                        top: 6,
                        bottom: 12,
                        left: 8,
                        right: 16,
                      ),
                      decoration: BoxDecoration(
                        gradient: LinearGradient(
                          begin: Alignment.topCenter,
                          end: Alignment.bottomCenter,
                          colors: [
                            Colors.black.withValues(alpha: 0.45),
                            Colors.transparent,
                          ],
                        ),
                      ),
                      child: Row(
                        children: [
                          IconButton(
                            icon: const Icon(Icons.arrow_back, color: Colors.white),
                            onPressed: () => Navigator.of(context).pop(),
                          ),
                          Expanded(
                            child: Text(
                              pack.titleFor(locale),
                              style: const TextStyle(
                                fontSize: 20,
                                fontWeight: FontWeight.w800,
                                color: Colors.white,
                              ),
                            ),
                          ),
                          Text(
                            '★ $totalStars/${pack.stages.length * 3}',
                            style: const TextStyle(
                              color: Colors.amber,
                              fontWeight: FontWeight.w700,
                            ),
                          ),
                        ],
                      ),
                    ),
                  ),
                ],
              ),
            ),
            const BannerAdSlot(),
          ],
        ),
      ),
    );
  }

  Widget _node(BuildContext context, MapLayout layout, int i, int count,
      int unlocked, int stars, ThemeColors colors, bool seasonComplete) {
    final center = layout.nodeCenter(i, count);
    final isCurrent = i == unlocked && !seasonComplete;
    final isUnlocked = i <= unlocked;
    final size = isCurrent ? 64.0 : 52.0;

    return Positioned(
      key: Key('stage_node_$i'),
      left: center.dx - size / 2,
      top: center.dy - size / 2,
      child: PressableScale(
        child: GestureDetector(
          onTap: !isUnlocked
              ? null
              : () {
                  ref
                      .read(seasonFlowProvider.notifier)
                      .startSeasonStage(widget.pack, i);
                  Navigator.of(context).push(
                    fadeRoute(const GameScreen()),
                  );
                },
          child: Column(
            mainAxisSize: MainAxisSize.min,
            children: [
              Container(
                width: size,
                height: size,
                alignment: Alignment.center,
                decoration: BoxDecoration(
                  shape: BoxShape.circle,
                  gradient: isUnlocked
                      ? LinearGradient(
                          begin: Alignment.topLeft,
                          end: Alignment.bottomRight,
                          colors: isCurrent
                              ? [
                                  lighten(colors.accent, 0.25),
                                  colors.accent,
                                  darken(colors.accent, 0.2),
                                ]
                              : [
                                  const Color(0xFFFFE9A8),
                                  const Color(0xFFFFD166),
                                  const Color(0xFFE0AC3B),
                                ],
                        )
                      : null,
                  color: isUnlocked ? null : GamePalette.lockedNode,
                  boxShadow: isCurrent
                      ? [
                          BoxShadow(
                            color: colors.accent.withValues(alpha: 0.7),
                            blurRadius: 22,
                          ),
                        ]
                      : null,
                ),
                child: isUnlocked
                    ? Text(
                        '${i + 1}',
                        style: TextStyle(
                          fontSize: isCurrent ? 22 : 17,
                          fontWeight: FontWeight.w900,
                          color: isCurrent
                              ? Colors.white
                              : const Color(0xFF5A4200),
                        ),
                      )
                    : const Icon(Icons.lock, color: Colors.white24, size: 20),
              ),
              if (isUnlocked && !isCurrent)
                Row(
                  mainAxisSize: MainAxisSize.min,
                  children: [
                    for (var s = 0; s < 3; s++)
                      Icon(
                        Icons.star,
                        size: 13,
                        color: s < stars ? Colors.amber : Colors.white24,
                      ),
                  ],
                ),
            ],
          ),
        ),
      ),
    );
  }
}

class _PathPainter extends CustomPainter {
  const _PathPainter({required this.layout, required this.count});

  final MapLayout layout;
  final int count;

  @override
  void paint(Canvas canvas, Size size) {
    if (count < 2) return;
    final path = Path()
      ..moveTo(
          layout.nodeCenter(0, count).dx, layout.nodeCenter(0, count).dy);
    for (var i = 1; i < count; i++) {
      final prev = layout.nodeCenter(i - 1, count);
      final cur = layout.nodeCenter(i, count);
      final midY = (prev.dy + cur.dy) / 2;
      path.cubicTo(prev.dx, midY, cur.dx, midY, cur.dx, cur.dy);
    }

    final paint = Paint()
      ..color = Colors.white.withValues(alpha: 0.25)
      ..style = PaintingStyle.stroke
      ..strokeWidth = 5
      ..strokeCap = StrokeCap.round;

    // Dash the path manually: short dots every 13px.
    for (final metric in path.computeMetrics()) {
      var d = 0.0;
      while (d < metric.length) {
        canvas.drawPath(metric.extractPath(d, d + 1.5), paint);
        d += 13;
      }
    }
  }

  @override
  bool shouldRepaint(_PathPainter old) =>
      old.count != count || old.layout.width != layout.width;
}
