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 '../../../core/api/api_exception.dart';
import '../../../core/auth/jwt_decoder.dart';
import '../../../core/l10n/l10n.dart';
import '../../../core/ui/async_state_views.dart';
import '../../auth/data/auth_providers.dart';
import '../data/recipe_providers.dart';
import '../domain/recipe.dart';
import '../domain/inventory_preview.dart';

String _fmtQty(double v) =>
    v == v.truncateToDouble() ? v.toInt().toString() : v.toString();

enum _ShareAction { share, unshare }

class RecipeDetailScreen extends ConsumerWidget {
  final int recipeId;

  const RecipeDetailScreen({super.key, required this.recipeId});

  @override
  Widget build(BuildContext context, WidgetRef ref) {
    final recipeAsync = ref.watch(recipeDetailProvider(recipeId));
    final token = ref.watch(authStateProvider).maybeWhen(
      data: (t) => t,
      orElse: () => null,
    );
    final currentUserId = jwtUserId(token);
    final recipe = recipeAsync.asData?.value;
    final isOwner = recipe != null && currentUserId != null && recipe.ownerId == currentUserId;

    return Scaffold(
      appBar: AppBar(
        title: const SizedBox.shrink(),
        leading: IconButton(
          icon: const Icon(Icons.arrow_back),
          onPressed: () => context.go('/recipes'),
          tooltip: context.l10n.recipeDetailBackToList,
        ),
        actions: recipe == null
            ? []
            : [
                if (isOwner)
                  IconButton(
                    tooltip: recipe.isPublic ? context.l10n.recipeDetailMakePrivate : context.l10n.recipeDetailMakePublic,
                    icon: Icon(recipe.isPublic ? Icons.public : Icons.lock_outline),
                    onPressed: () => _toggleVisibility(context, ref, recipe),
                  ),
                if (isOwner)
                  IconButton(
                    tooltip: context.l10n.recipeDetailShareWithUser,
                    icon: const Icon(Icons.person_add_alt_1_outlined),
                    onPressed: () => _shareRecipe(context, ref, recipe),
                  ),
                IconButton(
                  tooltip: context.l10n.editTooltip,
                  icon: const Icon(Icons.edit_outlined),
                  onPressed: () =>
                      context.push('/recipes/$recipeId/edit'),
                ),
                IconButton(
                  tooltip: context.l10n.recipeDetailGoToInventory,
                  icon: const Icon(Icons.inventory_2_outlined),
                  onPressed: () => context.go('/inventory'),
                ),
                if (isOwner) _DeleteButton(recipe: recipe),
              ],
      ),
      body: recipeAsync.when(
        loading: () => LoadingStateView(label: context.l10n.recipeDetailLoading),
        error: (error, _) => ErrorStateView(
          message: mapErrorToUserMessage(error, context),
          onRetry: () => ref.invalidate(recipeDetailProvider(recipeId)),
        ),
        data: (recipe) => CustomScrollView(
          physics: const BouncingScrollPhysics(),
          slivers: [
            SliverAppBar(
              expandedHeight: MediaQuery.of(context).size.height * 0.42,
              flexibleSpace: FlexibleSpaceBar(
                background: Stack(
                  fit: StackFit.expand,
                  children: [
                    recipe.imageUrl != null
                        ? Image.network(
                            recipe.imageUrl!,
                            fit: BoxFit.cover,
                            errorBuilder: (_, __, ___) => _ImagePlaceholder(),
                          )
                        : _ImagePlaceholder(),
                    // Gradient + title overlay
                    Positioned(
                      left: 0,
                      right: 0,
                      bottom: 0,
                      child: Container(
                        padding: const EdgeInsets.fromLTRB(16, 40, 16, 16),
                        decoration: const BoxDecoration(
                          gradient: LinearGradient(
                            begin: Alignment.topCenter,
                            end: Alignment.bottomCenter,
                            colors: [Colors.transparent, Colors.black87],
                          ),
                        ),
                        child: Text(
                          recipe.title,
                          style: const TextStyle(
                            color: Colors.white,
                            fontSize: 22,
                            fontWeight: FontWeight.bold,
                            shadows: [Shadow(blurRadius: 4, color: Colors.black54)],
                          ),
                        ),
                      ),
                    ),
                    if (recipe.isPublic &&
                        recipe.ownerUsername != null &&
                        recipe.ownerUsername!.isNotEmpty)
                      Positioned(
                        right: 12,
                        top: 12,
                        child: Container(
                          padding: const EdgeInsets.symmetric(horizontal: 10, vertical: 5),
                          decoration: BoxDecoration(
                            color: Colors.black.withOpacity(0.45),
                            borderRadius: BorderRadius.circular(14),
                          ),
                          child: Text(
                            '@${recipe.ownerUsername}',
                            style: const TextStyle(
                              color: Colors.white,
                              fontSize: 12,
                              fontWeight: FontWeight.w600,
                            ),
                          ),
                        ),
                      ),
                  ],
                ),
              ),
              pinned: true,
            ),
            SliverToBoxAdapter(
              child: Container(
                decoration: BoxDecoration(
                  color: Theme.of(context).colorScheme.surface,
                  borderRadius: const BorderRadius.only(
                    topLeft: Radius.circular(20),
                    topRight: Radius.circular(20),
                  ),
                ),
                child: _RecipeBody(recipe: recipe),
              ),
            ),
          ],
        ),
      ),
    );
  }

  Future<void> _toggleVisibility(
    BuildContext context,
    WidgetRef ref,
    Recipe recipe,
  ) async {
    try {
      final token = ref.read(authStateProvider).maybeWhen(
        data: (t) => t,
        orElse: () => null,
          ) ??
          await ref.read(authStateProvider.future);
      await ref.read(recipeRepositoryProvider).setRecipeVisibility(
            recipe.id,
            isPublic: !recipe.isPublic,
            token: token,
          );
      ref.invalidate(recipeDetailProvider(recipe.id));
      ref.invalidate(recipesProvider);
      if (!context.mounted) return;
      ScaffoldMessenger.of(context).showSnackBar(
        SnackBar(
          content: Text(
            !recipe.isPublic
                ? context.l10n.recipeDetailNowPublic
                : context.l10n.recipeDetailNowPrivate,
          ),
        ),
      );
    } on ApiException catch (e) {
      if (!context.mounted) return;
      ScaffoldMessenger.of(context).showSnackBar(
        SnackBar(content: Text(mapErrorToUserMessage(e, context))),
      );
    }
  }

  Future<void> _shareRecipe(
    BuildContext context,
    WidgetRef ref,
    Recipe recipe,
  ) async {
    final ctrl = TextEditingController();
    final result = await showDialog<(_ShareAction, String)>(
      context: context,
      builder: (context) => AlertDialog(
        title: Text(context.l10n.recipeDetailShareTitle),
        content: TextField(
          controller: ctrl,
          autofocus: true,
          decoration: InputDecoration(
            labelText: context.l10n.recipeDetailUsernameLabel,
            hintText: context.l10n.recipeDetailUsernameHint,
          ),
          onSubmitted: (_) => Navigator.pop(
            context,
            (_ShareAction.share, ctrl.text.trim()),
          ),
        ),
        actions: [
          TextButton(
            onPressed: () => Navigator.pop(context),
            child: Text(context.l10n.cancelAction),
          ),
          TextButton(
            onPressed: () => Navigator.pop(
              context,
              (_ShareAction.unshare, ctrl.text.trim()),
            ),
            child: Text(context.l10n.recipeDetailRemoveShare),
          ),
          FilledButton(
            onPressed: () => Navigator.pop(
              context,
              (_ShareAction.share, ctrl.text.trim()),
            ),
            child: Text(context.l10n.recipeDetailShareAction),
          ),
        ],
      ),
    );
    ctrl.dispose();

    final action = result?.$1;
    final trimmed = result?.$2.trim() ?? '';
    if (trimmed.isEmpty) return;

    try {
      final token = ref.read(authStateProvider).maybeWhen(
        data: (t) => t,
        orElse: () => null,
          ) ??
          await ref.read(authStateProvider.future);
      if (action == _ShareAction.unshare) {
        await ref.read(recipeRepositoryProvider).unshareRecipeWithUsername(
              recipe.id,
              username: trimmed,
              token: token,
            );
      } else {
        await ref.read(recipeRepositoryProvider).shareRecipeWithUsername(
              recipe.id,
              username: trimmed,
              token: token,
            );
      }
      ref.invalidate(recipeDetailProvider(recipe.id));
      if (!context.mounted) return;
      ScaffoldMessenger.of(context).showSnackBar(
        SnackBar(
          content: Text(
            action == _ShareAction.unshare
                ? context.l10n.recipeDetailSharingRemoved(trimmed)
                : context.l10n.recipeDetailSharedWith(trimmed),
          ),
        ),
      );
    } on ApiException catch (e) {
      if (!context.mounted) return;
      ScaffoldMessenger.of(context).showSnackBar(
        SnackBar(content: Text(mapErrorToUserMessage(e, context))),
      );
    }
  }
}

class _ImagePlaceholder extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Container(
      color: Theme.of(context).colorScheme.surfaceContainerHighest,
      child: Center(
        child: Icon(
          Icons.restaurant,
          size: 64,
          color: Theme.of(context).colorScheme.onSurfaceVariant.withOpacity(0.4),
        ),
      ),
    );
  }
}

class _DeleteButton extends ConsumerWidget {
  final Recipe recipe;

  const _DeleteButton({required this.recipe});

  @override
  Widget build(BuildContext context, WidgetRef ref) {
    return IconButton(
      tooltip: context.l10n.deleteTooltip,
      icon: const Icon(Icons.delete_outline),
      onPressed: () => _confirmDelete(context, ref),
    );
  }

  Future<void> _confirmDelete(BuildContext context, WidgetRef ref) async {
    final confirmed = await showDialog<bool>(
      context: context,
      builder: (_) => AlertDialog(
        title: Text(context.l10n.recipeDetailDeleteTitle),
        content: Text(context.l10n.recipeDetailDeleteContent(recipe.title)),
        actions: [
          TextButton(
            onPressed: () => Navigator.pop(context, false),
            child: Text(context.l10n.cancelAction),
          ),
          FilledButton(
            style: FilledButton.styleFrom(
                backgroundColor: Theme.of(context).colorScheme.error),
            onPressed: () => Navigator.pop(context, true),
            child: Text(context.l10n.deleteAction),
          ),
        ],
      ),
    );

    if (confirmed != true || !context.mounted) return;

    try {
      final token = ref.read(authStateProvider).maybeWhen(
        data: (t) => t,
        orElse: () => null,
          ) ??
          await ref.read(authStateProvider.future);
      await ref.read(recipeRepositoryProvider).deleteRecipe(recipe.id,
          token: token);
      ref.invalidate(recipesProvider);
      if (context.mounted) context.go('/recipes');
    } on ApiException catch (e) {
      if (!context.mounted) return;
      ScaffoldMessenger.of(context).showSnackBar(
        SnackBar(content: Text(mapErrorToUserMessage(e, context))),
      );
    }
  }
}

class _RecipeBody extends StatelessWidget {
  final Recipe recipe;

  const _RecipeBody({required this.recipe});

  @override
  Widget build(BuildContext context) {
    final theme = Theme.of(context);
    return Padding(
      padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 20),
      child: Column(
        crossAxisAlignment: CrossAxisAlignment.start,
        children: [
          // Titel visas som overlay på bilden — inte upprepas här
          if (recipe.description != null) ...[
            const SizedBox(height: 8),
            Text(recipe.description!,
                style: theme.textTheme.bodyMedium
                    ?.copyWith(color: theme.colorScheme.onSurfaceVariant)),
          ],
          if (recipe.servings != null) ...[
            const SizedBox(height: 8),
            Row(
              children: [
                const Icon(Icons.people_outline, size: 16),
                const SizedBox(width: 4),
                Text('${recipe.servings} ${context.l10n.recipeDetailServings}',
                    style: theme.textTheme.bodySmall),
              ],
            ),
          ],
          if (recipe.ingredients.isNotEmpty) ...[
            const SizedBox(height: 24),
            Text(context.l10n.recipeDetailIngredients, style: theme.textTheme.titleMedium),
            const SizedBox(height: 12),
            ...recipe.ingredients.map((ing) {
              final qtyStr = ing.quantity == 0 ? '' : _fmtQty(ing.quantity);
              final measureParts = [
                if (qtyStr.isNotEmpty) qtyStr,
                if (ing.unit.isNotEmpty) ing.unit,
              ];
              final measure = measureParts.join(' ');
              return Padding(
                padding: const EdgeInsets.symmetric(vertical: 5),
                child: Row(
                  crossAxisAlignment: CrossAxisAlignment.start,
                  children: [
                    if (measure.isNotEmpty) ...[
                      Container(
                        width: 72,
                        padding: const EdgeInsets.symmetric(
                            horizontal: 8, vertical: 2),
                        decoration: BoxDecoration(
                          color: theme.colorScheme.primaryContainer,
                          borderRadius: BorderRadius.circular(6),
                        ),
                        child: Text(
                          measure,
                          textAlign: TextAlign.center,
                          style: theme.textTheme.bodySmall?.copyWith(
                            color: theme.colorScheme.onPrimaryContainer,
                            fontWeight: FontWeight.w600,
                          ),
                        ),
                      ),
                      const SizedBox(width: 10),
                    ] else
                      const SizedBox(width: 82),
                    Expanded(
                      child: Text(
                        ing.note != null
                            ? '${ing.productName} (${ing.note})'
                            : ing.productName,
                        style: theme.textTheme.bodyMedium,
                      ),
                    ),
                  ],
                ),
              );
            }),
          ],
          if (recipe.instructions != null &&
              recipe.instructions!.isNotEmpty) ...[
            const SizedBox(height: 32),
            Text(context.l10n.recipeDetailInstructions, style: theme.textTheme.titleMedium),
            const SizedBox(height: 16),
            ..._buildSteps(recipe.instructions!, theme),
          ],
          _InventoryPreviewSection(recipeId: recipe.id),
          const SizedBox(height: 40),
        ],
      ),
    );
  }

  List<Widget> _buildSteps(String instructions, ThemeData theme) {
    final steps = instructions
        .split(RegExp(r'\n{2,}'))
        .map((s) => s.trim())
        .where((s) => s.isNotEmpty)
        .toList();

    return steps.asMap().entries.map((entry) {
      final index = entry.key + 1;
      final text = entry.value;
      return Padding(
        padding: const EdgeInsets.only(bottom: 20),
        child: Row(
          crossAxisAlignment: CrossAxisAlignment.start,
          children: [
            Container(
              width: 32,
              height: 32,
              alignment: Alignment.center,
              decoration: BoxDecoration(
                color: theme.colorScheme.primary,
                shape: BoxShape.circle,
              ),
              child: Text(
                '$index',
                style: TextStyle(
                  color: theme.colorScheme.onPrimary,
                  fontWeight: FontWeight.bold,
                  fontSize: 14,
                ),
              ),
            ),
            const SizedBox(width: 12),
            Expanded(
              child: Padding(
                padding: const EdgeInsets.only(top: 6),
                child: Text(
                  text,
                  style: theme.textTheme.bodyMedium?.copyWith(height: 1.6),
                ),
              ),
            ),
          ],
        ),
      );
    }).toList();
  }
}

class _InventoryPreviewSection extends ConsumerStatefulWidget {
  final int recipeId;

  const _InventoryPreviewSection({required this.recipeId});

  @override
  ConsumerState<_InventoryPreviewSection> createState() =>
      _InventoryPreviewSectionState();
}

class _InventoryPreviewSectionState
    extends ConsumerState<_InventoryPreviewSection> {
  bool _loaded = false;

  @override
  Widget build(BuildContext context) {
    final theme = Theme.of(context);
    return Column(
      crossAxisAlignment: CrossAxisAlignment.start,
      children: [
        const SizedBox(height: 24),
        Row(
          children: [
            Text('Vad saknas?', style: theme.textTheme.titleMedium),
            const Spacer(),
            if (!_loaded)
              FilledButton.tonalIcon(
                onPressed: () => setState(() => _loaded = true),
                icon: const Icon(Icons.search, size: 16),
                label: const Text('Kontrollera inventarie'),
              ),
            if (_loaded)
              IconButton(
                tooltip: 'Uppdatera',
                icon: const Icon(Icons.refresh),
                onPressed: () {
                  ref.invalidate(inventoryPreviewProvider(widget.recipeId));
                },
              ),
          ],
        ),
        if (_loaded) _InventoryPreviewResults(recipeId: widget.recipeId),
      ],
    );
  }
}

class _InventoryPreviewResults extends ConsumerWidget {
  final int recipeId;

  const _InventoryPreviewResults({required this.recipeId});

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

    return previewAsync.when(
      loading: () => const Padding(
        padding: EdgeInsets.symmetric(vertical: 16),
        child: Center(child: CircularProgressIndicator()),
      ),
      error: (error, _) => Padding(
        padding: const EdgeInsets.only(top: 8),
        child: Text(
          mapErrorToUserMessage(error, context),
          style: TextStyle(color: theme.colorScheme.error),
        ),
      ),
      data: (preview) {
        final summary = preview.summary;
        return Column(
          crossAxisAlignment: CrossAxisAlignment.start,
          children: [
            const SizedBox(height: 8),
            _SummaryChips(summary: summary),
            const SizedBox(height: 12),
            ...preview.ingredients.map(
              (ing) => _IngredientPreviewRow(ingredient: ing),
            ),
          ],
        );
      },
    );
  }
}

class _SummaryChips extends StatelessWidget {
  final PreviewSummary summary;

  const _SummaryChips({required this.summary});

  @override
  Widget build(BuildContext context) {
    final theme = Theme.of(context);
    final cs = theme.colorScheme;
    return Wrap(
      spacing: 8,
      runSpacing: 4,
      children: [
        if (summary.canCookExactly)
          Chip(
            avatar: Icon(Icons.check_circle,
                color: cs.onPrimary, size: 16),
            label: const Text('Kan lagas!'),
            backgroundColor: cs.primary,
            labelStyle: TextStyle(color: cs.onPrimary),
          )
        else
          Chip(
            avatar: Icon(Icons.warning_amber,
                color: cs.onErrorContainer, size: 16),
            label: Text('Saknar ${summary.missingCount} ingrediens'
                '${summary.missingCount == 1 ? '' : 'er'}'),
            backgroundColor: cs.errorContainer,
            labelStyle: TextStyle(color: cs.onErrorContainer),
          ),
        if (summary.unitMismatchCount > 0)
          Chip(
            avatar: Icon(Icons.swap_horiz,
                color: cs.onTertiaryContainer, size: 16),
            label: Text('${summary.unitMismatchCount} enhetsmismatch'),
            backgroundColor: cs.tertiaryContainer,
            labelStyle: TextStyle(color: cs.onTertiaryContainer),
          ),
      ],
    );
  }
}

class _IngredientPreviewRow extends StatelessWidget {
  final IngredientPreview ingredient;

  const _IngredientPreviewRow({required this.ingredient});

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

    final (icon, color) = switch (ingredient.status) {
      IngredientStatus.enough => (Icons.check_circle_outline, cs.primary),
      IngredientStatus.unitMismatch => (
          Icons.swap_horiz,
          cs.tertiary,
        ),
      IngredientStatus.missing => (Icons.cancel_outlined, cs.error),
    };

    final requiredStr =
        '${_fmtQty(ingredient.requiredQuantity)} ${ingredient.requiredUnit}'.trim();
    final availableStr =
        '${_fmtQty(ingredient.availableQuantity)} ${ingredient.requiredUnit}'.trim();

    final subtitle = switch (ingredient.status) {
      IngredientStatus.enough => 'Tillgängligt: $availableStr',
      IngredientStatus.missing => ingredient.availableQuantity > 0
          ? 'Saknar ${_fmtQty(ingredient.missingQuantity)} ${ingredient.requiredUnit} '
              '(har $availableStr)'
          : 'Saknas helt',
      IngredientStatus.unitMismatch =>
        'Annan enhet i lager – kontrollera manuellt',
    };

    return Padding(
      padding: const EdgeInsets.symmetric(vertical: 4),
      child: Row(
        crossAxisAlignment: CrossAxisAlignment.start,
        children: [
          Icon(icon, color: color, size: 18),
          const SizedBox(width: 8),
          Expanded(
            child: Column(
              crossAxisAlignment: CrossAxisAlignment.start,
              children: [
                Text(
                  '${ingredient.productName}'
                  '${ingredient.note != null ? ' (${ingredient.note})' : ''}'
                  ' – $requiredStr',
                  style: theme.textTheme.bodyMedium,
                ),
                Text(
                  subtitle,
                  style: theme.textTheme.bodySmall
                      ?.copyWith(color: color),
                ),
              ],
            ),
          ),
        ],
      ),
    );
  }
}
