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

import '../../../core/api/api_error_mapper.dart';
import '../../auth/data/auth_providers.dart';
import '../data/inventory_providers.dart';
import '../domain/inventory_item.dart';

/// Returns a sensible step size for quick swipe-adjustments given [unit].
///
/// Examples: "g" → 50, "kg" → 0.1, "ml" → 50, "l" / "dl" → 0.1,
/// everything else (pieces, packages, etc.) → 1.
double _stepForUnit(String unit) {
  switch (unit.trim().toLowerCase()) {
    case 'g':
    case 'gram':
      return 50;
    case 'kg':
    case 'kilo':
    case 'kilogram':
      return 0.1;
    case 'ml':
      return 50;
    case 'cl':
      return 1;
    case 'dl':
      return 0.5;
    case 'l':
    case 'liter':
    case 'litre':
      return 0.1;
    default:
      return 1;
  }
}

/// Formats a step value for display: whole numbers without decimal,
/// fractions with one decimal.
String _fmtStep(double step) =>
    step == step.roundToDouble() ? step.toStringAsFixed(0) : step.toStringAsFixed(1);

/// A [ListTile] wrapped in a swipe-to-adjust widget.
///
/// • Swipe **right** (+) → adds one unit-appropriate step via PATCH.
/// • Swipe **left**  (−) → consumes one unit-appropriate step via the
///   consume endpoint, preserving consumption history.
///
/// The step size is determined by the item's unit (e.g. 50 g, 0.1 kg, 1 st).
/// A small swipe-hint icon is shown at the start of the subtitle so users
/// know the gesture is available without any extra instruction.
class SwipeableInventoryTile extends ConsumerStatefulWidget {
  final InventoryItem item;

  const SwipeableInventoryTile({super.key, required this.item});

  @override
  ConsumerState<SwipeableInventoryTile> createState() =>
      _SwipeableInventoryTileState();
}

class _SwipeableInventoryTileState
    extends ConsumerState<SwipeableInventoryTile> {
  /// Pixels dragged horizontally. Positive = right, negative = left.
  double _drag = 0;

  /// While true, ignore new drag gestures (API call in flight).
  bool _acting = false;

  static const _threshold = 72.0; // minimum drag to trigger an action
  static const _maxReveal = 88.0; // maximum horizontal travel shown

  // ── Gesture handlers ────────────────────────────────────────────────────

  void _onUpdate(DragUpdateDetails d) {
    if (_acting) return;
    setState(() {
      _drag = (_drag + d.delta.dx).clamp(-_maxReveal, _maxReveal);
    });
  }

  void _onEnd(DragEndDetails d) {
    if (_acting) return;
    if (_drag > _threshold) {
      _adjust(1);
    } else if (_drag < -_threshold) {
      _adjust(-1);
    }
    _snapBack();
  }

  void _snapBack() => setState(() => _drag = 0);

  Future<void> _adjust(int direction) async {
    final step = _stepForUnit(widget.item.unit);
    setState(() => _acting = true);
    try {
      final token = await ref.read(authStateProvider.future);
      final repo = ref.read(inventoryRepositoryProvider);

      if (direction > 0) {
        // Increase: direct PATCH with new quantity.
        await repo.updateInventoryItem(
          widget.item.id,
          {'quantity': widget.item.quantity + step},
          token: token,
        );
      } else {
        // Decrease: use consume endpoint so history is preserved.
        // Guard against going below zero.
        if (widget.item.quantity <= 0) return;
        final consume = step > widget.item.quantity ? widget.item.quantity : step;
        await repo.consumeInventoryItem(
          widget.item.id,
          amountUsed: consume,
          token: token,
        );
      }

      ref.invalidate(inventoryProvider);
    } catch (e) {
      if (!mounted) return;
      ScaffoldMessenger.of(context).showSnackBar(
        SnackBar(content: Text(mapErrorToUserMessage(e, context))),
      );
    } finally {
      if (mounted) setState(() => _acting = false);
    }
  }

  // ── Build ────────────────────────────────────────────────────────────────

  @override
  Widget build(BuildContext context) {
    final theme = Theme.of(context);
    final colorScheme = theme.colorScheme;

    // How far (0.0–1.0) we are from triggering an action, used for opacity.
    final rightProgress = (_drag / _threshold).clamp(0.0, 1.0);
    final leftProgress = (-_drag / _threshold).clamp(0.0, 1.0);

    final step = _stepForUnit(widget.item.unit);
    final stepLabel = _fmtStep(step);
    final unit = widget.item.unit;

    return GestureDetector(
      onHorizontalDragUpdate: _onUpdate,
      onHorizontalDragEnd: _onEnd,
      onHorizontalDragCancel: _snapBack,
      behavior: HitTestBehavior.opaque,
      child: ClipRect(
        child: Stack(
          children: [
            // ── Right-swipe background (add +1) ─────────────────────────
            Positioned.fill(
              child: Row(
                children: [
                  Expanded(
                    child: Opacity(
                      opacity: rightProgress,
                      child: Container(
                        color: colorScheme.primaryContainer,
                        alignment: Alignment.centerLeft,
                        padding: const EdgeInsets.only(left: 20),
                        child: Column(
                          mainAxisSize: MainAxisSize.min,
                          children: [
                            Icon(
                              Icons.add_circle_outline,
                              color: colorScheme.onPrimaryContainer,
                            ),
                            const SizedBox(height: 2),
                            Text(
                              '+$stepLabel $unit',
                              style: theme.textTheme.labelSmall?.copyWith(
                                color: colorScheme.onPrimaryContainer,
                                fontWeight: FontWeight.bold,
                              ),
                            ),
                          ],
                        ),
                      ),
                    ),
                  ),
                ],
              ),
            ),

            // ── Left-swipe background (remove −1) ───────────────────────
            Positioned.fill(
              child: Row(
                children: [
                  const Spacer(),
                  Expanded(
                    child: Opacity(
                      opacity: leftProgress,
                      child: Container(
                        color: colorScheme.tertiaryContainer,
                        alignment: Alignment.centerRight,
                        padding: const EdgeInsets.only(right: 20),
                        child: Column(
                          mainAxisSize: MainAxisSize.min,
                          children: [
                            Icon(
                              Icons.remove_circle_outline,
                              color: colorScheme.onTertiaryContainer,
                            ),
                            const SizedBox(height: 2),
                            Text(
                              '−$stepLabel $unit',
                              style: theme.textTheme.labelSmall?.copyWith(
                                color: colorScheme.onTertiaryContainer,
                                fontWeight: FontWeight.bold,
                              ),
                            ),
                          ],
                        ),
                      ),
                    ),
                  ),
                ],
              ),
            ),

            // ── Foreground tile ─────────────────────────────────────────
            Transform.translate(
              offset: Offset(_drag, 0),
              child: _ForegroundTile(item: widget.item, acting: _acting),
            ),
          ],
        ),
      ),
    );
  }
}

// ── Foreground tile ──────────────────────────────────────────────────────────

class _ForegroundTile extends ConsumerWidget {
  final InventoryItem item;
  final bool acting;

  const _ForegroundTile({required this.item, required this.acting});

  @override
  Widget build(BuildContext context, WidgetRef ref) {
    final theme = Theme.of(context);

    final subtitleText = [
      '${_fmtQty(item.quantity)} ${item.unit}',
      if (item.location != null && item.location!.isNotEmpty) item.location!,
      if (item.bestBeforeDate != null)
        'Bäst före: ${_formatDate(item.bestBeforeDate!)}',
    ].join(' · ');

    return ColoredBox(
      // Opaque background so the tile sits on top of the reveal panels.
      color: theme.colorScheme.surface,
      child: ListTile(
        title: Text(item.productName),
        // Subtitle: small swipe-hint icon + text on the same row.
        subtitle: Row(
          children: [
            Icon(
              Icons.swap_horiz,
              size: 13,
              color: theme.colorScheme.outline,
            ),
            const SizedBox(width: 3),
            Expanded(
              child: Text(
                subtitleText,
                overflow: TextOverflow.ellipsis,
              ),
            ),
          ],
        ),
        trailing: acting
            ? const SizedBox(
                width: 24,
                height: 24,
                child: CircularProgressIndicator(strokeWidth: 2),
              )
            : _TrailingActions(item: item),
        onTap: () => context.push('/inventory/${item.id}'),
      ),
    );
  }

  String _fmtQty(double v) =>
      v == v.roundToDouble() ? v.toStringAsFixed(0) : v.toStringAsFixed(1);

  String _formatDate(String iso) {
    try {
      final dt = DateTime.parse(iso);
      return '${dt.year}-${dt.month.toString().padLeft(2, '0')}-'
          '${dt.day.toString().padLeft(2, '0')}';
    } catch (_) {
      return iso;
    }
  }
}

// ── Trailing action buttons ─────────────────────────────────────────────────

class _TrailingActions extends ConsumerWidget {
  final InventoryItem item;

  const _TrailingActions({required this.item});

  @override
  Widget build(BuildContext context, WidgetRef ref) {
    return Row(
      mainAxisSize: MainAxisSize.min,
      children: [
        if (item.opened)
          const Padding(
            padding: EdgeInsets.only(right: 4),
            child: Chip(
              label: Text('Öppnad'),
              padding: EdgeInsets.zero,
              visualDensity: VisualDensity.compact,
            ),
          ),
        Tooltip(
          message: 'Konsumera',
          child: IconButton(
            icon: const Icon(Icons.remove_circle_outline),
            onPressed: () => context.push('/inventory/${item.id}/consume'),
          ),
        ),
        Tooltip(
          message: 'Redigera',
          child: IconButton(
            icon: const Icon(Icons.edit_outlined),
            onPressed: () => context.push('/inventory/${item.id}/edit'),
          ),
        ),
        _DeleteButton(item: item),
      ],
    );
  }
}

class _DeleteButton extends ConsumerWidget {
  final InventoryItem item;

  const _DeleteButton({required this.item});

  @override
  Widget build(BuildContext context, WidgetRef ref) {
    return Tooltip(
      message: 'Ta bort',
      child: IconButton(
        icon: const Icon(Icons.delete_outline, color: Colors.red),
        onPressed: () async {
          final confirmed = await showDialog<bool>(
            context: context,
            builder: (ctx) => AlertDialog(
              title: const Text('Ta bort inventariepost?'),
              content: Text('Vill du ta bort "${item.productName}"?'),
              actions: [
                TextButton(
                  onPressed: () => Navigator.pop(ctx, false),
                  child: const Text('Avbryt'),
                ),
                FilledButton(
                  onPressed: () => Navigator.pop(ctx, true),
                  child: const Text('Ta bort'),
                ),
              ],
            ),
          );
          if (confirmed == true) {
            try {
              final token = await ref.read(authStateProvider.future);
              await ref
                  .read(inventoryRepositoryProvider)
                  .deleteInventoryItem(item.id, token: token);
              ref.invalidate(inventoryProvider);
            } catch (e) {
              ScaffoldMessenger.of(context).showSnackBar(
                SnackBar(content: Text(mapErrorToUserMessage(e, context))),
              );
            }
          }
        },
      ),
    );
  }
}
