import 'dart:async';

import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:kasy_kit/core/dev_inspector/dev_inspector_info.dart';
import 'package:kasy_kit/core/dev_inspector/dev_inspector_service.dart';
import 'package:kasy_kit/core/icons/kasy_icons.dart';
import 'package:kasy_kit/core/theme/colors.dart';
import 'package:kasy_kit/core/theme/extensions/theme_extension.dart';
import 'package:kasy_kit/core/theme/providers/theme_provider.dart';
import 'package:kasy_kit/i18n/translations.g.dart';
import 'package:shared_preferences/shared_preferences.dart';

final GlobalKey<ScaffoldMessengerState> devInspectorRootScaffoldMessengerKey =
    GlobalKey<ScaffoldMessengerState>(debugLabel: 'devInspectorRoot');

/// Persisted flag — Settings (admin, debug only) toggles this; [DevInspector] listens.
const String devInspectorFabEnabledPrefKey = 'dev_inspector_fab_enabled';

final ValueNotifier<bool> devInspectorFabEnabledNotifier =
    ValueNotifier<bool>(false);

/// Set to true to reveal the FAB immediately (bypasses the startup delay).
/// [DevInspector] resets it back to false after consuming the signal.
final ValueNotifier<bool> devInspectorRevealNowNotifier =
    ValueNotifier<bool>(false);

/// Set to true to trigger a copy of the currently selected widget.
/// [DevInspector] handles the copy + feedback and resets this to false.
final ValueNotifier<bool> devInspectorCopyTriggerNotifier =
    ValueNotifier<bool>(false);

class DevInspector extends StatefulWidget {
  const DevInspector({super.key, required this.child});

  final Widget child;

  static Widget wrap({required Widget child}) {
    if (!kDebugMode) return child;
    return DevInspector(child: child);
  }

  @override
  State<DevInspector> createState() => _DevInspectorState();
}

class _DevInspectorState extends State<DevInspector> {
  static const Duration _fabRevealDelay = Duration(seconds: 2);
  static const Duration _fabDeemphasizeDelay = Duration(seconds: 2);
  static const Duration _fabOpacityAnimation = Duration(milliseconds: 700);
  static const double _fabOpacityIdle = 0.75;
  static const double _fabOpacityInspectorOn = 1.0;
  static const Duration _copyFeedbackVisible = Duration(milliseconds: 2200);
  /// Horizontal inset from the right so the banner does not sit under the FAB.
  static const double _copyFeedbackRightInset = 68;

  bool _active = false;
  bool _copyBusy = false;

  double? _fabDx;
  double? _fabDy;
  bool _dragging = false;

  Timer? _revealTimer;
  Timer? _fabDeemphasizeTimer;
  Timer? _copyFeedbackTimer;
  String? _copyFeedbackText;
  bool _copyFeedbackIsError = false;
  bool _fabLayerMounted = false;
  bool _fabFadeIn = false;
  bool _fabEmphasized = false;

  @override
  void initState() {
    super.initState();
    WidgetsBinding.instance.debugShowWidgetInspectorOverrideNotifier
        .addListener(_handleInspectorOverrideChanged);
    devInspectorFabEnabledNotifier.addListener(_onFabEnabledNotifierChanged);
    devInspectorRevealNowNotifier.addListener(_onRevealNow);
    devInspectorCopyTriggerNotifier.addListener(_onCopyTriggered);
    unawaited(_bootstrapFabPreference());
  }

  @override
  void dispose() {
    _revealTimer?.cancel();
    _fabDeemphasizeTimer?.cancel();
    _copyFeedbackTimer?.cancel();
    devInspectorFabEnabledNotifier.removeListener(_onFabEnabledNotifierChanged);
    devInspectorRevealNowNotifier.removeListener(_onRevealNow);
    devInspectorCopyTriggerNotifier.removeListener(_onCopyTriggered);
    WidgetsBinding.instance.debugShowWidgetInspectorOverrideNotifier
        .removeListener(_handleInspectorOverrideChanged);
    if (_active) {
      WidgetsBinding.instance.debugShowWidgetInspectorOverride = false;
    }
    super.dispose();
  }

  Future<void> _bootstrapFabPreference() async {
    final SharedPreferences prefs = await SharedPreferences.getInstance();
    if (!mounted) return;
    final bool enabled = prefs.getBool(devInspectorFabEnabledPrefKey) ?? false;
    final bool changed = devInspectorFabEnabledNotifier.value != enabled;
    devInspectorFabEnabledNotifier.value = enabled;
    if (!changed) {
      _applyFabEnabled(enabled);
    }
  }

  void _onFabEnabledNotifierChanged() {
    _applyFabEnabled(devInspectorFabEnabledNotifier.value);
  }

  void _onCopyTriggered() {
    if (!devInspectorCopyTriggerNotifier.value) return;
    devInspectorCopyTriggerNotifier.value = false;
    if (!_active) return;
    unawaited(_copySelection());
  }

  void _onRevealNow() {
    if (!devInspectorRevealNowNotifier.value) return;
    devInspectorRevealNowNotifier.value = false;
    if (!devInspectorFabEnabledNotifier.value || !mounted) return;
    _revealTimer?.cancel();
    setState(() {
      _fabLayerMounted = true;
      _fabFadeIn = false;
    });
    WidgetsBinding.instance.addPostFrameCallback((_) {
      if (!mounted) return;
      setState(() => _fabFadeIn = true);
    });
  }

  void _applyFabEnabled(bool enabled) {
    _revealTimer?.cancel();
    _fabDeemphasizeTimer?.cancel();
    if (!mounted) return;
    if (!enabled) {
      if (_active) {
        WidgetsBinding.instance.debugShowWidgetInspectorOverride = false;
      }
      _copyFeedbackTimer?.cancel();
      setState(() {
        _active = false;
        _fabLayerMounted = false;
        _fabFadeIn = false;
        _fabEmphasized = false;
        _dragging = false;
        _copyFeedbackText = null;
        _copyFeedbackIsError = false;
      });
      _copyFeedbackTimer?.cancel();
      return;
    }
    setState(() {
      _fabLayerMounted = false;
      _fabFadeIn = false;
    });
    _revealTimer = Timer(_fabRevealDelay, _onFabRevealDelayElapsed);
  }

  void _onFabRevealDelayElapsed() {
    if (!mounted) return;
    setState(() {
      _fabLayerMounted = true;
      _fabFadeIn = false;
    });
    WidgetsBinding.instance.addPostFrameCallback((_) {
      if (!mounted) return;
      setState(() => _fabFadeIn = true);
    });
  }

  void _scheduleFabDeemphasize() {
    _fabDeemphasizeTimer?.cancel();
    _fabDeemphasizeTimer = Timer(_fabDeemphasizeDelay, () {
      if (!mounted) return;
      setState(() => _fabEmphasized = false);
      _fabDeemphasizeTimer = null;
    });
  }

  double get _fabAnimatedOpacity {
    if (!_fabLayerMounted) return 0.0;
    if (!_fabFadeIn) return 0.0;
    if (_dragging || _copyBusy || _fabEmphasized) return 1.0;
    return _active ? _fabOpacityInspectorOn : _fabOpacityIdle;
  }

  void _setInspectorActive(bool value) {
    setState(() => _active = value);
    WidgetsBinding.instance.debugShowWidgetInspectorOverride = value;
    HapticFeedback.lightImpact();
  }

  void _handleInspectorOverrideChanged() {
    final bool override =
        WidgetsBinding.instance.debugShowWidgetInspectorOverride;
    if (_active == override) return;
    if (!mounted) return;
    setState(() => _active = override);
  }

  String? _extractRouteHint(DevInspectorInfo info) {
    final RegExp routeRegex = RegExp(r'(Page|Screen|Route|View)$');
    for (final String type in info.ancestors.reversed) {
      if (routeRegex.hasMatch(type)) return type;
    }
    return null;
  }

  void _showCopyFeedback(String message, {required bool isError}) {
    _copyFeedbackTimer?.cancel();
    setState(() {
      _copyFeedbackText = message;
      _copyFeedbackIsError = isError;
    });
    _copyFeedbackTimer = Timer(_copyFeedbackVisible, () {
      if (!mounted) return;
      setState(() {
        _copyFeedbackText = null;
        _copyFeedbackIsError = false;
      });
      _copyFeedbackTimer = null;
    });
  }

  Future<void> _copySelection() async {
    if (!_active || _copyBusy) return;
    _copyBusy = true;
    try {
      final DevInspectorInfo? info = DevInspectorService.inspectSelected();
      if (!mounted) return;
      if (info == null) {
        _showCopyFeedback(t.devInspector.selectWidgetFirst, isError: true);
        HapticFeedback.heavyImpact();
        return;
      }

      await Clipboard.setData(
        ClipboardData(
          text: info.toAIClipboard(routeName: _extractRouteHint(info)),
        ),
      );
      if (!mounted) return;
      _showCopyFeedback(
        t.devInspector.copied(widget: info.widgetType),
        isError: false,
      );
      HapticFeedback.selectionClick();
    } finally {
      _copyBusy = false;
    }
  }

  (Size, EdgeInsets) _sizeAndPadding(BuildContext context) {
    final MediaQueryData? mq = MediaQuery.maybeOf(context);
    if (mq != null) return (mq.size, mq.padding);
    final view = View.of(context);
    final double dpr = view.devicePixelRatio;
    return (
      Size(view.physicalSize.width / dpr, view.physicalSize.height / dpr),
      EdgeInsets.fromViewPadding(view.padding, dpr),
    );
  }

  static TextDirection _platformTextDirection() {
    final String lang =
        WidgetsBinding.instance.platformDispatcher.locale.languageCode;
    const Set<String> rtl = {'ar', 'fa', 'he', 'ur'};
    return rtl.contains(lang.toLowerCase())
        ? TextDirection.rtl
        : TextDirection.ltr;
  }

  @override
  Widget build(BuildContext context) {
    final (Size size, EdgeInsets padding) = _sizeAndPadding(context);
    final AppTheme appTheme = ThemeProvider.of(context);
    final ThemeData shellTheme = switch (appTheme.mode) {
      ThemeMode.dark => appTheme.dark,
      ThemeMode.light => appTheme.light,
      ThemeMode.system =>
        WidgetsBinding.instance.platformDispatcher.platformBrightness ==
                Brightness.dark
            ? appTheme.dark
            : appTheme.light,
    };

    return Directionality(
      textDirection: _platformTextDirection(),
      child: Theme(
        data: shellTheme,
        child: Builder(
          builder: (BuildContext context) {
            final KasyColors colors = context.colors;

            // Default: bottom-right, just above the home bottom nav (still draggable).
            // ~16px from right; larger bottom inset → sits a bit higher above the bar.
            _fabDx ??= size.width - 68.0;
            _fabDy ??= size.height - padding.bottom - 152.0;

            return Stack(
              clipBehavior: Clip.none,
              children: <Widget>[
                widget.child,
                if (_fabLayerMounted &&
                    devInspectorFabEnabledNotifier.value)
                  Positioned(
                    left: _fabDx,
                    top: _fabDy,
                    child: AnimatedOpacity(
                      opacity: _fabAnimatedOpacity,
                      duration: _fabOpacityAnimation,
                      curve: Curves.easeOutCubic,
                      child: GestureDetector(
                        onTapDown: (_) => setState(() => _fabEmphasized = true),
                        onTap: () {
                          if (_active) {
                            _copySelection().whenComplete(
                              _scheduleFabDeemphasize,
                            );
                          } else {
                            _setInspectorActive(true);
                            _scheduleFabDeemphasize();
                          }
                        },
                        onPanStart: (_) => setState(() {
                          _dragging = true;
                          _fabEmphasized = true;
                        }),
                        onPanUpdate: (DragUpdateDetails details) {
                          setState(() {
                            _fabDx = (_fabDx! + details.delta.dx).clamp(
                              8.0,
                              size.width - 60.0,
                            );
                            _fabDy = (_fabDy! + details.delta.dy).clamp(
                              padding.top + 8.0,
                              size.height - padding.bottom - 60.0,
                            );
                          });
                        },
                        onPanEnd: (_) {
                          if (!mounted) return;
                          setState(() => _dragging = false);
                          _scheduleFabDeemphasize();
                        },
                        child: _EntryFab(
                          dragging: _dragging,
                          active: _active,
                          busy: _copyBusy,
                          colors: colors,
                        ),
                      ),
                    ),
                  ),
                if (_copyFeedbackText != null)
                  Positioned(
                    left: 16,
                    right: 16 + _copyFeedbackRightInset,
                    bottom: padding.bottom + 12,
                    child: IgnorePointer(
                      child: Builder(
                        builder: (BuildContext ctx) {
                          final ThemeData theme = Theme.of(ctx);
                          final ColorScheme scheme = theme.colorScheme;
                          final Color bg = _copyFeedbackIsError
                              ? scheme.error
                              : scheme.inverseSurface;
                          final Color fg = _copyFeedbackIsError
                              ? scheme.onError
                              : scheme.onInverseSurface;
                          return Material(
                            elevation: 12,
                            shadowColor: Colors.black45,
                            borderRadius: BorderRadius.circular(12),
                            color: bg,
                            child: Padding(
                              padding: const EdgeInsets.symmetric(
                                horizontal: 16,
                                vertical: 12,
                              ),
                              child: Text(
                                _copyFeedbackText!,
                                style: theme.textTheme.bodyMedium?.copyWith(
                                  color: fg,
                                  fontWeight: FontWeight.w500,
                                ),
                              ),
                            ),
                          );
                        },
                      ),
                    ),
                  ),
              ],
            );
          },
        ),
      ),
    );
  }
}

class _EntryFab extends StatelessWidget {
  const _EntryFab({
    required this.dragging,
    required this.active,
    required this.busy,
    required this.colors,
  });

  final bool dragging;
  final bool active;
  final bool busy;
  final KasyColors colors;

  @override
  Widget build(BuildContext context) {
    return Semantics(
      label: active ? t.devInspector.copyForAi : t.devInspector.activate,
      button: true,
      child: AnimatedContainer(
        duration: const Duration(milliseconds: 180),
        width: 52,
        height: 52,
        decoration: BoxDecoration(
          color: colors.surface,
          shape: BoxShape.circle,
          border: Border.all(
            color: colors.onSurface.withValues(alpha: 0.14),
            width: 1.5,
          ),
          boxShadow: <BoxShadow>[
            BoxShadow(
              color: colors.onSurface.withValues(alpha: dragging ? 0.20 : 0.08),
              blurRadius: dragging ? 18 : 10,
              offset: Offset(0, dragging ? 6 : 3),
            ),
          ],
        ),
        child: busy
            ? SizedBox(
                width: 20,
                height: 20,
                child: CircularProgressIndicator(
                  strokeWidth: 2,
                  valueColor: AlwaysStoppedAnimation<Color>(colors.primary),
                ),
              )
            : Icon(
                active ? KasyIcons.copy : KasyIcons.widgets,
                color: colors.primary,
                size: 22,
              ),
      ),
    );
  }
}
