import 'dart:math' as math;

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

import '../../app/icons/app_icons.dart';
import '../../app/theme/app_colors.dart';
import '../../core/providers/theme_provider.dart';
import '../../data/local/hive_boxes.dart';
import '../../data/local/models/app_settings.dart';

/// 5-tab bottom navigation bar with luxury active treatment.
class AppBottomNavBar extends ConsumerStatefulWidget {
  const AppBottomNavBar({
    super.key,
    required this.currentIndex,
    required this.onTap,
  });

  final int currentIndex;
  final ValueChanged<int> onTap;

  @override
  ConsumerState<AppBottomNavBar> createState() => _AppBottomNavBarState();
}

class _AppBottomNavBarState extends ConsumerState<AppBottomNavBar>
    with TickerProviderStateMixin {
  static const double _toggleRevealWidth = 88;
  static const double _dragThreshold = 38;
  static const double _inactiveIconSize = 27;
  static const double _activeIconSize = 22;
  static const double _navIconStrokeWidth = 1.9;
  late final AnimationController _shineController;
  late final AnimationController _revealController;
  late final Animation<double> _revealAnimation;
  bool _isThemeToggleOpen = false;
  double _dragDeltaX = 0;

  @override
  void initState() {
    super.initState();
    _shineController = AnimationController(
      vsync: this,
      duration: const Duration(milliseconds: 5200),
    )..repeat();
    _revealController = AnimationController(
      vsync: this,
      duration: const Duration(milliseconds: 340),
    );
    _revealAnimation = CurvedAnimation(
      parent: _revealController,
      curve: Curves.easeOutCubic,
      reverseCurve: Curves.easeInCubic,
    );
  }

  void _syncAnimation({required bool reducedMotion}) {
    if (reducedMotion) {
      if (_shineController.isAnimating) {
        _shineController.stop(canceled: false);
      }
      return;
    }

    if (!_shineController.isAnimating) {
      _shineController.repeat();
    }
  }

  void _openThemeToggle({bool withHaptics = true}) {
    if (_isThemeToggleOpen) return;
    _isThemeToggleOpen = true;
    if (withHaptics) {
      HapticFeedback.mediumImpact();
    }
    _revealController.animateTo(1);
  }

  void _closeThemeToggle({bool withHaptics = true}) {
    if (!_isThemeToggleOpen) return;
    _isThemeToggleOpen = false;
    if (withHaptics) {
      HapticFeedback.lightImpact();
    }
    _revealController.animateBack(0);
  }

  void _handleNavTap(int index) {
    _closeThemeToggle(withHaptics: false);
    widget.onTap(index);
  }

  void _handleHorizontalDragStart(DragStartDetails _) {
    _dragDeltaX = 0;
  }

  void _handleHorizontalDragUpdate(DragUpdateDetails details) {
    _dragDeltaX += details.delta.dx;
  }

  void _handleHorizontalDragEnd(DragEndDetails details) {
    final velocityX = details.primaryVelocity ?? 0;
    final shouldOpen = velocityX < -220 || _dragDeltaX <= -_dragThreshold;
    final shouldClose = velocityX > 220 || _dragDeltaX >= _dragThreshold;

    if (shouldOpen && !_isThemeToggleOpen) {
      _openThemeToggle();
    } else if (shouldClose && _isThemeToggleOpen) {
      _closeThemeToggle();
    }
  }

  Future<void> _toggleThemeMode(BuildContext context) async {
    final isDarkNow = Theme.of(context).brightness == Brightness.dark;
    final nextMode = isDarkNow ? ThemeMode.light : ThemeMode.dark;
    final box = Hive.box<AppSettings>(HiveBoxes.settings);
    final settings = box.get('default') ?? AppSettings();

    settings.themeModeIndex = nextMode == ThemeMode.dark ? 2 : 1;

    if (settings.isInBox) {
      await settings.save();
    } else {
      await box.put('default', settings);
    }

    ref.read(themeProvider.notifier).state = nextMode;
    HapticFeedback.selectionClick();

    if (mounted) {
      _closeThemeToggle(withHaptics: false);
    }
  }

  @override
  void dispose() {
    _shineController.dispose();
    _revealController.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    final media = MediaQuery.maybeOf(context);
    final reducedMotion = (media?.disableAnimations ?? false) ||
        (media?.accessibleNavigation ?? false);
    _syncAnimation(reducedMotion: reducedMotion);

    return ValueListenableBuilder<Box<AppSettings>>(
      valueListenable: Hive.box<AppSettings>(HiveBoxes.settings).listenable(),
      builder: (context, box, _) {
        final isSimpleMode = box.get('default')?.simpleMode ?? false;
        final isDark = Theme.of(context).brightness == Brightness.dark;
        final systemBottomInset =
            MediaQueryData.fromView(View.of(context)).viewPadding.bottom;

        final items = isSimpleMode
            ? const [
                _NavDef(AppIcons.home, 'Beranda'),
                _NavDef(AppIcons.calendar, 'Jadwal'),
                _NavDef(AppIcons.quran, "Al-Qur'an"),
                _NavDef(AppIcons.dzikir, 'Dzikir'),
                _NavDef(AppIcons.lainnya, 'Lainnya'),
              ]
            : const [
                _NavDef(AppIcons.home, 'Beranda'),
                _NavDef(AppIcons.calendar, 'Jadwal'),
                _NavDef(AppIcons.ibadah, 'Ibadah'),
                _NavDef(AppIcons.laporan, 'Laporan'),
                _NavDef(AppIcons.lainnya, 'Lainnya'),
              ];

        return ColoredBox(
          color: Theme.of(context).bottomNavigationBarTheme.backgroundColor ??
              Colors.transparent,
          child: Padding(
            padding: EdgeInsets.fromLTRB(10, 6, 10, 6 + systemBottomInset),
            child: GestureDetector(
              behavior: HitTestBehavior.deferToChild,
              onHorizontalDragStart: _handleHorizontalDragStart,
              onHorizontalDragUpdate: _handleHorizontalDragUpdate,
              onHorizontalDragEnd: _handleHorizontalDragEnd,
              child: SizedBox(
                height: 56,
                child: Stack(
                  clipBehavior: Clip.none,
                  children: [
                    Positioned.fill(
                      child: AnimatedBuilder(
                        animation: _revealController,
                        builder: (context, child) {
                          final reveal = _revealAnimation.value;
                          return IgnorePointer(
                            ignoring: reveal < 0.55,
                            child: _ThemeUnderlayBoard(
                              isDark: isDark,
                              reveal: reveal,
                              onTap: () => _toggleThemeMode(context),
                            ),
                          );
                        },
                      ),
                    ),
                    AnimatedBuilder(
                      animation: _revealController,
                      builder: (context, child) {
                        final reveal = _revealAnimation.value;
                        return Transform.translate(
                          offset: Offset(-_toggleRevealWidth * reveal, 0),
                          child: _MainNavBoard(
                            items: items,
                            currentIndex: widget.currentIndex,
                            isDark: isDark,
                            reducedMotion: reducedMotion,
                            animation: _shineController,
                            onTap: _handleNavTap,
                          ),
                        );
                      },
                    ),
                  ],
                ),
              ),
            ),
          ),
        );
      },
    );
  }
}

class _ThemeUnderlayBoard extends StatelessWidget {
  const _ThemeUnderlayBoard({
    required this.isDark,
    required this.reveal,
    required this.onTap,
  });

  final bool isDark;
  final double reveal;
  final VoidCallback onTap;

  @override
  Widget build(BuildContext context) {
    final t = reveal.clamp(0.0, 1.0).toDouble();
    return Container(
      height: 54,
      decoration: BoxDecoration(
        borderRadius: BorderRadius.circular(28),
        color: isDark ? const Color(0xFF090D14) : const Color(0xFFE6E6EA),
        border: Border.all(
          color: isDark ? const Color(0x1FFFFFFF) : const Color(0x140F172A),
          width: 0.8,
        ),
      ),
      child: Align(
        alignment: Alignment.centerRight,
        child: SizedBox(
          width: _AppBottomNavBarState._toggleRevealWidth,
          child: Material(
            color: Colors.transparent,
            child: InkWell(
              onTap: onTap,
              borderRadius: BorderRadius.circular(22),
              child: Center(
                child: Opacity(
                  opacity: t,
                  child: Transform.translate(
                    offset: Offset((1 - t) * 10, 0),
                    child: Transform.scale(
                      scale: 0.94 + (t * 0.06),
                      child: AppIcon(
                        glyph: isDark ? AppIcons.themeSun : AppIcons.themeMoon,
                        size: 24,
                        color: isDark
                            ? AppColors.navActiveGoldPale
                            : AppColors.textPrimaryLight,
                      ),
                    ),
                  ),
                ),
              ),
            ),
          ),
        ),
      ),
    );
  }
}

class _NavDef {
  const _NavDef(this.icon, this.label);

  final AppIconGlyph icon;
  final String label;
}

class _MainNavBoard extends StatelessWidget {
  const _MainNavBoard({
    required this.items,
    required this.currentIndex,
    required this.isDark,
    required this.reducedMotion,
    required this.animation,
    required this.onTap,
  });

  final List<_NavDef> items;
  final int currentIndex;
  final bool isDark;
  final bool reducedMotion;
  final Animation<double> animation;
  final ValueChanged<int> onTap;

  @override
  Widget build(BuildContext context) {
    final background =
        Theme.of(context).bottomNavigationBarTheme.backgroundColor ??
            (isDark ? AppColors.surfaceDark : AppColors.surfaceLight);

    return DecoratedBox(
      decoration: BoxDecoration(
        color: background,
        borderRadius: BorderRadius.circular(28),
      ),
      child: Row(
        children: List.generate(items.length, (index) {
          final item = items[index];
          final isSelected = index == currentIndex;
          return Expanded(
            child: Material(
              color: Colors.transparent,
              child: InkWell(
                onTap: () => onTap(index),
                customBorder: RoundedRectangleBorder(
                  borderRadius: BorderRadius.circular(22),
                ),
                child: SizedBox(
                  height: 56,
                  child: Center(
                    child: isSelected
                        ? _AnimatedLuxuryActiveIcon(
                            animation: animation,
                            icon: item.icon,
                            isDark: isDark,
                            reducedMotion: reducedMotion,
                            iconSize: _AppBottomNavBarState._activeIconSize,
                          )
                        : _InactiveNavIcon(
                            glyph: item.icon,
                            isDark: isDark,
                            iconSize: _AppBottomNavBarState._inactiveIconSize,
                          ),
                  ),
                ),
              ),
            ),
          );
        }),
      ),
    );
  }
}

class _InactiveNavIcon extends StatelessWidget {
  const _InactiveNavIcon({
    required this.glyph,
    required this.isDark,
    required this.iconSize,
  });

  final AppIconGlyph glyph;
  final bool isDark;
  final double iconSize;

  @override
  Widget build(BuildContext context) {
    return SizedBox(
      width: 48,
      height: 48,
      child: Center(
        child: AppIcon(
          glyph: glyph,
          size: iconSize,
          strokeWidth: _AppBottomNavBarState._navIconStrokeWidth,
          color: isDark
              ? AppColors.textSecondaryDark
              : AppColors.textSecondaryLight,
        ),
      ),
    );
  }
}

class _AnimatedLuxuryActiveIcon extends StatelessWidget {
  const _AnimatedLuxuryActiveIcon({
    required this.animation,
    required this.icon,
    required this.isDark,
    required this.reducedMotion,
    required this.iconSize,
  });

  final Animation<double> animation;
  final AppIconGlyph icon;
  final bool isDark;
  final bool reducedMotion;
  final double iconSize;

  @override
  Widget build(BuildContext context) {
    return RepaintBoundary(
      child: AnimatedBuilder(
        animation: animation,
        builder: (_, __) {
          return _LuxuryActiveIcon(
            icon: icon,
            isDark: isDark,
            reducedMotion: reducedMotion,
            progress: reducedMotion ? 0.17 : animation.value,
            iconSize: iconSize,
          );
        },
      ),
    );
  }
}

class _LuxuryActiveIcon extends StatelessWidget {
  const _LuxuryActiveIcon({
    required this.icon,
    required this.isDark,
    required this.reducedMotion,
    required this.progress,
    required this.iconSize,
  });

  final AppIconGlyph icon;
  final bool isDark;
  final bool reducedMotion;
  final double progress;
  final double iconSize;

  @override
  Widget build(BuildContext context) {
    final baseShadow = isDark
        ? <BoxShadow>[
            const BoxShadow(
              color: Color(0xB3000000),
              blurRadius: 9,
              spreadRadius: 0.2,
              offset: Offset(0, 4),
            ),
            const BoxShadow(
              color: AppColors.navGlowDark,
              blurRadius: 8,
              spreadRadius: -0.8,
              offset: Offset(0, 1.5),
            ),
          ]
        : <BoxShadow>[
            const BoxShadow(
              color: AppColors.navEmbossHighlight,
              blurRadius: 3.2,
              offset: Offset(-1.1, -1.1),
            ),
            const BoxShadow(
              color: AppColors.navEmbossShadow,
              blurRadius: 7,
              offset: Offset(2.3, 3.1),
            ),
          ];

    return SizedBox(
      width: 48,
      height: 48,
      child: Container(
        decoration: BoxDecoration(
          color: isDark ? const Color(0xFF11161F) : const Color(0xFFF2F3F5),
          borderRadius: BorderRadius.circular(15),
          border: Border.all(
            color: isDark ? const Color(0x383D4C61) : const Color(0x2610172A),
            width: 0.85,
          ),
          boxShadow: baseShadow,
        ),
        child: Padding(
          padding: const EdgeInsets.all(2.0),
          child: DecoratedBox(
            decoration: BoxDecoration(
              color: isDark
                  ? const Color(0xFF1A202A)
                  : AppColors.navActiveSurfaceLight,
              borderRadius: BorderRadius.circular(12.5),
              border: Border.all(
                color:
                    isDark ? const Color(0x2EFFFFFF) : const Color(0x1F0F172A),
                width: 0.8,
              ),
            ),
            child: CustomPaint(
              painter: _LuxuryRingPainter(
                progress: progress,
                reducedMotion: reducedMotion,
                isDark: isDark,
              ),
              child: Center(
                child: AppIcon(
                  glyph: icon,
                  size: iconSize,
                  strokeWidth: _AppBottomNavBarState._navIconStrokeWidth,
                  color: isDark
                      ? AppColors.textPrimaryDark
                      : AppColors.textPrimaryLight,
                ),
              ),
            ),
          ),
        ),
      ),
    );
  }
}

class _LuxuryRingPainter extends CustomPainter {
  const _LuxuryRingPainter({
    required this.progress,
    required this.reducedMotion,
    required this.isDark,
  });

  final double progress;
  final bool reducedMotion;
  final bool isDark;

  @override
  void paint(Canvas canvas, Size size) {
    final rect = Offset.zero & size;
    final outerRect = rect.deflate(1.05);
    final ringRect = rect.deflate(2.5);
    final innerRect = rect.deflate(4.75);

    final outerRRect =
        RRect.fromRectAndRadius(outerRect, const Radius.circular(12.4));
    final ringRRect =
        RRect.fromRectAndRadius(ringRect, const Radius.circular(10.8));
    final innerRRect =
        RRect.fromRectAndRadius(innerRect, const Radius.circular(9.1));
    final rotation = reducedMotion ? math.pi * 0.63 : progress * math.pi * 2;

    void drawEmboss(
      RRect target, {
      required Offset shadowOffset,
      required Offset highlightOffset,
      required Color shadowColor,
      required Color highlightColor,
      required double shadowBlur,
      required double highlightBlur,
      required double strokeWidth,
    }) {
      final shadowPaint = Paint()
        ..style = PaintingStyle.stroke
        ..strokeWidth = strokeWidth
        ..color = shadowColor
        ..maskFilter = MaskFilter.blur(BlurStyle.normal, shadowBlur);

      final highlightPaint = Paint()
        ..style = PaintingStyle.stroke
        ..strokeWidth = strokeWidth
        ..color = highlightColor
        ..maskFilter = MaskFilter.blur(BlurStyle.normal, highlightBlur);

      canvas.save();
      canvas.translate(shadowOffset.dx, shadowOffset.dy);
      canvas.drawRRect(target, shadowPaint);
      canvas.restore();

      canvas.save();
      canvas.translate(highlightOffset.dx, highlightOffset.dy);
      canvas.drawRRect(target, highlightPaint);
      canvas.restore();
    }

    drawEmboss(
      outerRRect,
      shadowOffset: const Offset(0.7, 1.0),
      highlightOffset: const Offset(-0.6, -0.7),
      shadowColor: isDark
          ? const Color(0xD6000000)
          : AppColors.navEmbossShadow.withValues(alpha: 0.72),
      highlightColor: isDark
          ? Colors.white.withValues(alpha: 0.22)
          : Colors.white.withValues(alpha: 0.92),
      shadowBlur: isDark ? 2.5 : 1.8,
      highlightBlur: isDark ? 1.6 : 1.1,
      strokeWidth: 1.05,
    );

    drawEmboss(
      innerRRect,
      shadowOffset: const Offset(-0.45, -0.35),
      highlightOffset: const Offset(0.45, 0.55),
      shadowColor: isDark
          ? Colors.black.withValues(alpha: 0.58)
          : AppColors.navEmbossShadow.withValues(alpha: 0.58),
      highlightColor: isDark
          ? Colors.white.withValues(alpha: 0.14)
          : Colors.white.withValues(alpha: 0.78),
      shadowBlur: isDark ? 1.5 : 1.2,
      highlightBlur: isDark ? 1.1 : 0.9,
      strokeWidth: 0.88,
    );

    final metallicRing = SweepGradient(
      startAngle: rotation,
      endAngle: rotation + math.pi * 2,
      colors: const [
        AppColors.navActiveGoldDeep,
        AppColors.navActiveGold,
        AppColors.navActiveGoldBright,
        AppColors.navActiveGoldPale,
        AppColors.navActiveGoldBright,
        AppColors.navActiveGoldDeep,
      ],
      stops: const [0.0, 0.16, 0.34, 0.5, 0.68, 1.0],
    );

    final metallicPaint = Paint()
      ..style = PaintingStyle.stroke
      ..strokeWidth = 1.9
      ..shader = metallicRing.createShader(ringRect)
      ..isAntiAlias = true;

    final chromaStrength = isDark ? 0.92 : 0.74;
    final chromaSweep = SweepGradient(
      startAngle: (rotation * 1.3) + 0.42,
      endAngle: (rotation * 1.3) + 0.42 + math.pi * 2,
      colors: [
        Colors.transparent,
        Colors.transparent,
        AppColors.navActiveGold.withValues(alpha: 0.52 * chromaStrength),
        Colors.white.withValues(alpha: 0.94 * chromaStrength),
        AppColors.navActiveGoldPale.withValues(alpha: 0.68 * chromaStrength),
        Colors.transparent,
        Colors.transparent,
        AppColors.navActiveGold.withValues(alpha: 0.44 * chromaStrength),
        Colors.white.withValues(alpha: 0.88 * chromaStrength),
        AppColors.navActiveGoldPale.withValues(alpha: 0.64 * chromaStrength),
        Colors.transparent,
        Colors.transparent,
      ],
      stops: const [
        0.0,
        0.09,
        0.112,
        0.126,
        0.14,
        0.175,
        0.45,
        0.468,
        0.484,
        0.5,
        0.528,
        1.0,
      ],
    );

    final chromaPaint = Paint()
      ..style = PaintingStyle.stroke
      ..strokeWidth = 1.15
      ..shader = chromaSweep.createShader(ringRect)
      ..blendMode = BlendMode.screen;

    canvas.drawRRect(ringRRect, metallicPaint);
    canvas.drawRRect(ringRRect, chromaPaint);

    final ambientGold = Paint()
      ..style = PaintingStyle.stroke
      ..strokeWidth = isDark ? 1.0 : 0.85
      ..color = isDark
          ? AppColors.navActiveGold.withValues(alpha: 0.18)
          : AppColors.navActiveGoldDeep.withValues(alpha: 0.16)
      ..maskFilter = MaskFilter.blur(
        BlurStyle.normal,
        isDark ? 2.6 : 1.2,
      );
    canvas.drawRRect(ringRRect, ambientGold);

    final innerEdge = Paint()
      ..style = PaintingStyle.stroke
      ..strokeWidth = 0.8
      ..color = isDark
          ? Colors.white.withValues(alpha: 0.12)
          : const Color(0x330F172A);
    canvas.drawRRect(innerRRect, innerEdge);
  }

  @override
  bool shouldRepaint(covariant _LuxuryRingPainter oldDelegate) {
    return oldDelegate.progress != progress ||
        oldDelegate.reducedMotion != reducedMotion ||
        oldDelegate.isDark != isDark;
  }
}
