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/api/api_paths.dart';
import '../../../core/api/api_providers.dart';
import '../../../core/forms/form_options.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/recipe_ingredient.dart';

class _EditableIngredient {
  int? productId;
  String productName;
  final TextEditingController quantityCtrl;
  String unit;
  final TextEditingController noteCtrl;

  _EditableIngredient({
    required this.productId,
    required this.productName,
    required String quantity,
    required this.unit,
    String note = '',
  })  : quantityCtrl = TextEditingController(text: quantity),
        noteCtrl = TextEditingController(text: note);

  factory _EditableIngredient.fromRecipe(RecipeIngredient ingredient) {
    final quantity = ingredient.quantity == ingredient.quantity.truncateToDouble()
        ? ingredient.quantity.toInt().toString()
        : ingredient.quantity.toString();
    return _EditableIngredient(
      productId: ingredient.productId,
      productName: ingredient.productName,
      quantity: quantity,
      unit: ingredient.unit,
      note: ingredient.note ?? '',
    );
  }

  void dispose() {
    quantityCtrl.dispose();
    noteCtrl.dispose();
  }
}

class RecipeEditScreen extends ConsumerStatefulWidget {
  final int recipeId;

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

  @override
  ConsumerState<RecipeEditScreen> createState() => _RecipeEditScreenState();
}

class _RecipeEditScreenState extends ConsumerState<RecipeEditScreen> {
  final _formKey = GlobalKey<FormState>();
  bool _initialized = false;

  late TextEditingController _nameCtrl;
  late TextEditingController _descCtrl;
  late TextEditingController _servingsCtrl;
  late TextEditingController _instructionsCtrl;
  final List<_EditableIngredient> _ingredients = [];
  List<Map<String, dynamic>> _allProducts = [];
  bool _isLoadingProducts = false;

  bool _isSaving = false;
  String? _saveError;

  @override
  void initState() {
    super.initState();
    _loadProducts();
  }

  @override
  void dispose() {
    if (_initialized) {
      _nameCtrl.dispose();
      _descCtrl.dispose();
      _servingsCtrl.dispose();
      _instructionsCtrl.dispose();
      for (final ingredient in _ingredients) {
        ingredient.dispose();
      }
    }
    super.dispose();
  }

  void _initControllers(Recipe recipe) {
    _nameCtrl = TextEditingController(text: recipe.title);
    _descCtrl = TextEditingController(text: recipe.description ?? '');
    _servingsCtrl =
        TextEditingController(text: recipe.servings?.toString() ?? '');
    _instructionsCtrl =
        TextEditingController(text: recipe.instructions ?? '');
    _ingredients
      ..clear()
      ..addAll(recipe.ingredients.map(_EditableIngredient.fromRecipe));
    _initialized = true;
  }

  Future<void> _loadProducts() async {
    setState(() => _isLoadingProducts = true);
    try {
      final token = await ref.read(authStateProvider.future);
      final api = ref.read(apiClientProvider);
      final data = await api.getJson(ProductApiPaths.list, token: token);
      if (!mounted) return;
      final products = (data as List<dynamic>)
          .map((e) => e as Map<String, dynamic>)
          .toList()
        ..sort((a, b) {
          final aName = (a['canonicalName'] ?? a['name'] ?? '').toString();
          final bName = (b['canonicalName'] ?? b['name'] ?? '').toString();
          return aName.toLowerCase().compareTo(bName.toLowerCase());
        });
      setState(() {
        _allProducts = products;
        _isLoadingProducts = false;
      });
    } catch (_) {
      if (!mounted) return;
      setState(() => _isLoadingProducts = false);
    }
  }

  void _addIngredient() {
    setState(() {
      _ingredients.add(
        _EditableIngredient(
          productId: null,
          productName: '',
          quantity: '',
          unit: 'st',
        ),
      );
    });
  }

  void _removeIngredient(int index) {
    setState(() {
      final ingredient = _ingredients.removeAt(index);
      ingredient.dispose();
    });
  }

  String? _validateIngredients() {
    if (_ingredients.isEmpty) {
      return context.l10n.recipeEditMinIngredients;
    }
    for (final ingredient in _ingredients) {
      if (ingredient.productId == null) {
        return context.l10n.recipeEditSelectProduct;
      }
      final quantity = double.tryParse(
        ingredient.quantityCtrl.text.trim().replaceAll(',', '.'),
      );
      if (quantity == null || quantity < 0) {
        return context.l10n.recipeEditValidQuantity;
      }
      if (ingredient.unit.trim().isEmpty) {
        return context.l10n.recipeEditSelectUnit;
      }
    }
    return null;
  }

  Future<void> _save() async {
    if (!(_formKey.currentState?.validate() ?? false)) return;

    final ingredientError = _validateIngredients();
    if (ingredientError != null) {
      setState(() => _saveError = ingredientError);
      return;
    }

    setState(() {
      _isSaving = true;
      _saveError = null;
    });

    try {
      final token = await ref.read(authStateProvider.future);
      final servings = int.tryParse(_servingsCtrl.text.trim());
      final ingredients = _ingredients
          .map(
            (ingredient) => {
              'productId': ingredient.productId,
              'quantity': double.parse(
                ingredient.quantityCtrl.text.trim().replaceAll(',', '.'),
              ),
              'unit': ingredient.unit,
              if (ingredient.noteCtrl.text.trim().isNotEmpty)
                'note': ingredient.noteCtrl.text.trim(),
            },
          )
          .toList();
      await ref.read(recipeRepositoryProvider).updateRecipe(
        widget.recipeId,
        {
          'name': _nameCtrl.text.trim(),
          'description': _descCtrl.text.trim().isEmpty
              ? null
              : _descCtrl.text.trim(),
          if (servings != null) 'servings': servings,
          'instructions': _instructionsCtrl.text.trim().isEmpty
              ? null
              : _instructionsCtrl.text.trim(),
          'ingredients': ingredients,
        },
        token: token,
      );
      ref.invalidate(recipeDetailProvider(widget.recipeId));
      ref.invalidate(recipesProvider);
      if (mounted) context.go('/recipes/${widget.recipeId}');
    } on ApiException catch (e) {
      if (e.type == ApiErrorType.unauthorized) {
        await ref.read(authStateProvider.notifier).logout();
        return;
      }
      setState(() {
        _saveError = mapErrorToUserMessage(e, context);
        _isSaving = false;
      });
    }
  }

  @override
  Widget build(BuildContext context) {
    final recipeAsync = ref.watch(recipeDetailProvider(widget.recipeId));

    return Scaffold(
      appBar: AppBar(
        title: Text(context.l10n.recipeEditTitle),
        actions: [
          if (_initialized)
            TextButton(
              onPressed: _isSaving ? null : _save,
              child: _isSaving
                  ? const SizedBox(
                      height: 16,
                      width: 16,
                      child: CircularProgressIndicator(strokeWidth: 2),
                    )
                  : Text(context.l10n.saveAction),
            ),
        ],
      ),
      body: recipeAsync.when(
        loading: () => LoadingStateView(label: context.l10n.recipeDetailLoading),
        error: (error, _) => ErrorStateView(
          message: mapErrorToUserMessage(error, context),
          onRetry: () => ref.invalidate(recipeDetailProvider(widget.recipeId)),
        ),
        data: (recipe) {
          if (!_initialized) _initControllers(recipe);
          return _buildForm(context);
        },
      ),
    );
  }

  Widget _buildForm(BuildContext context) {
    return SingleChildScrollView(
      padding: const EdgeInsets.all(16),
      child: Form(
        key: _formKey,
        child: Column(
          crossAxisAlignment: CrossAxisAlignment.stretch,
          children: [
            TextFormField(
              controller: _nameCtrl,
              decoration: InputDecoration(labelText: context.l10n.recipeEditNameLabel),
              validator: (v) =>
                  (v == null || v.trim().isEmpty) ? context.l10n.recipeEditNameRequired : null,
            ),
            const SizedBox(height: 16),
            TextFormField(
              controller: _descCtrl,
              decoration:
                  InputDecoration(labelText: context.l10n.recipeEditDescriptionLabel),
              maxLines: 3,
            ),
            const SizedBox(height: 16),
            TextFormField(
              controller: _servingsCtrl,
              decoration:
                  InputDecoration(labelText: context.l10n.recipeEditServingsLabel),
              keyboardType: TextInputType.number,
              validator: (v) {
                if (v == null || v.trim().isEmpty) return null;
                if (int.tryParse(v.trim()) == null) {
                  return context.l10n.recipeEditServingsInvalid;
                }
                return null;
              },
            ),
            const SizedBox(height: 16),
            TextFormField(
              controller: _instructionsCtrl,
              decoration:
                  InputDecoration(labelText: context.l10n.recipeEditInstructionsLabel),
              maxLines: 10,
              textAlignVertical: TextAlignVertical.top,
            ),
            const SizedBox(height: 20),
            Row(
              children: [
                Expanded(
                  child: Text(
                    context.l10n.recipeEditIngredientsLabel,
                    style: Theme.of(context).textTheme.titleMedium,
                  ),
                ),
                OutlinedButton.icon(
                  onPressed: _isSaving ? null : _addIngredient,
                  icon: const Icon(Icons.add),
                  label: Text(context.l10n.addAction),
                ),
              ],
            ),
            const SizedBox(height: 8),
            Text(
              context.l10n.recipeEditIngredientsHint,
              style: Theme.of(context).textTheme.bodySmall?.copyWith(
                  color: Theme.of(context).colorScheme.onSurfaceVariant),
            ),
            const SizedBox(height: 8),
            if (_isLoadingProducts)
              const Padding(
                padding: EdgeInsets.symmetric(vertical: 8),
                child: LinearProgressIndicator(),
              ),
            if (_ingredients.isEmpty)
              Card(
                child: Padding(
                  padding: const EdgeInsets.all(16),
                  child: Text(context.l10n.recipeEditNoIngredients),
                ),
              ),
            ...List.generate(
              _ingredients.length,
              (index) => _buildIngredientCard(context, index),
            ),
            if (_saveError != null) ...[
              const SizedBox(height: 16),
              Text(
                _saveError!,
                style:
                    TextStyle(color: Theme.of(context).colorScheme.error),
                textAlign: TextAlign.center,
              ),
            ],
            const SizedBox(height: 24),
            FilledButton(
              onPressed: _isSaving ? null : _save,
              child: _isSaving
                  ? const SizedBox(
                      height: 18,
                      width: 18,
                      child: CircularProgressIndicator(strokeWidth: 2),
                    )
                  : Text(context.l10n.recipeEditSaveChanges),
            ),
            const SizedBox(height: 40),
          ],
        ),
      ),
    );
  }

  Widget _buildIngredientCard(BuildContext context, int index) {
    final ingredient = _ingredients[index];
    return Card(
      margin: const EdgeInsets.only(bottom: 12),
      child: Padding(
        padding: const EdgeInsets.all(12),
        child: Column(
          children: [
            Row(
              children: [
                Expanded(
                  child: Text(
                    '${context.l10n.recipeEditIngredientPrefix}${index + 1}',
                    style: Theme.of(context).textTheme.titleSmall,
                  ),
                ),
                IconButton(
                  onPressed: _isSaving ? null : () => _removeIngredient(index),
                  icon: const Icon(Icons.delete_outline),
                  tooltip: context.l10n.recipeEditRemoveIngredient,
                ),
              ],
            ),
            DropdownButtonFormField<int>(
              initialValue: ingredient.productId,
              isExpanded: true,
              decoration: const InputDecoration(
                labelText: 'Produkt *',
                border: OutlineInputBorder(),
              ),
              items: _allProducts
                  .map(
                    (product) => DropdownMenuItem<int>(
                      value: product['id'] as int,
                      child: Text(
                        ((product['canonicalName'] ?? product['name']) as Object)
                            .toString(),
                        overflow: TextOverflow.ellipsis,
                      ),
                    ),
                  )
                  .toList(),
              onChanged: (_isSaving || _isLoadingProducts)
                  ? null
                  : (value) {
                      if (value == null) return;
                      final product = _allProducts.firstWhere(
                        (item) => item['id'] == value,
                        orElse: () => {'name': ''},
                      );
                      setState(() {
                        ingredient.productId = value;
                        ingredient.productName =
                            ((product['canonicalName'] ?? product['name']) as Object)
                                .toString();
                      });
                    },
            ),
            const SizedBox(height: 12),
            Row(
              crossAxisAlignment: CrossAxisAlignment.start,
              children: [
                Expanded(
                  child: TextFormField(
                    controller: ingredient.quantityCtrl,
                    decoration: InputDecoration(
                      labelText: context.l10n.quantityLabel,
                      border: const OutlineInputBorder(),
                    ),
                    keyboardType:
                        const TextInputType.numberWithOptions(decimal: true),
                    validator: (value) {
                      if (value == null || value.trim().isEmpty) {
                        return context.l10n.quantityHint;
                      }
                      if (double.tryParse(value.trim().replaceAll(',', '.')) ==
                          null) {
                        return context.l10n.invalidNumber;
                      }
                      return null;
                    },
                  ),
                ),
                const SizedBox(width: 12),
                Expanded(
                  child: DropdownButtonFormField<String>(
                    initialValue: ingredient.unit.trim().isEmpty ? null : ingredient.unit,
                    isExpanded: true,
                    decoration: InputDecoration(
                      labelText: context.l10n.unitLabel,
                      border: const OutlineInputBorder(),
                    ),
                    items: unitOptions
                        .map(
                          (option) => DropdownMenuItem<String>(
                            value: option.value,
                            child: Text(option.label, overflow: TextOverflow.ellipsis),
                          ),
                        )
                        .toList(),
                    onChanged: _isSaving
                        ? null
                        : (value) =>
                            setState(() => ingredient.unit = value ?? ''),
                  ),
                ),
              ],
            ),
            const SizedBox(height: 12),
            TextFormField(
              controller: ingredient.noteCtrl,
              decoration: const InputDecoration(
                labelText: 'Notering (valfritt)',
                border: OutlineInputBorder(),
              ),
            ),
          ],
        ),
      ),
    );
  }
}
