/// AddExpenseDialog
/// =================
///
/// A comprehensive dialog widget for creating or editing an expense within a group.
/// This dialog supports multi-currency, receipt image upload, flexible splitting (equal or custom),
/// and integrates with the ExpenseBloc for state management.
///
/// ## Features
/// - Form for entering expense details: description, amount, currency, category, date, payer, splits
/// - Receipt image upload with file size validation (max 5MB)
/// - Split expense equally or custom among group members
/// - Multi-currency support with automatic conversion to EUR
/// - Category selection with icons
/// - Date picker for expense date
/// - Paid by selection from group members
/// - Real-time split calculation and validation
/// - Form validation and error feedback
/// - Loading state during submission
/// - Integrates with ExpenseBloc for create/update actions
/// - Handles both creation and editing of expenses
///
/// ## Usage Example
/// ```dart
/// showDialog(
///   context: context,
///   builder: (context) => AddExpenseDialog(
///     group: group,
///     currentUser: user,
///     expenseToEdit: existingExpense, // null for new expense
///   ),
/// );
/// ```
///
/// ## State Management
/// - Uses ExpenseBloc for dispatching CreateExpense and UpdateExpense events
/// - Reads exchange rates from ExpensesLoaded state for currency conversion
///
/// ## Validation
/// - Description: required
/// - Amount: required, positive number
/// - Splits: at least one participant, total must match amount
/// - Receipt: optional, max 5MB
///
/// ## Accessibility
/// - All form fields have labels and icons
/// - Keyboard and screen reader friendly
///
/// ## Dependencies
/// - flutter_bloc
/// - image_picker
/// - intl
/// - Custom models: Expense, ExpenseSplit, Group
///
/// ## See also
/// - Expense
/// - Group
/// - ExpenseBloc
library;

import 'dart:io';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:image_picker/image_picker.dart';
import 'package:intl/intl.dart';
import 'package:travel_mate/models/expense_split.dart';
import '../../services/error_service.dart';
import '../../blocs/expense/expense_bloc.dart';
import '../../blocs/expense/expense_event.dart';
import '../../blocs/expense/expense_state.dart';
import '../../blocs/user/user_state.dart' as user_state;
import '../../models/group.dart';
import '../../models/expense.dart';

/// A dialog for creating or editing an expense in a group.
///
/// Accepts the group, current user, and optionally an expense to edit.
/// Shows a form for all expense details, supports receipt upload, and flexible splitting.
class AddExpenseDialog extends StatefulWidget {
  /// The group to which the expense belongs.
  final Group group;

  /// The user creating or editing the expense.
  final user_state.UserModel currentUser;

  /// The expense to edit (null for new expense).
  final Expense? expenseToEdit;

  /// Optional initial category for a new expense.
  final ExpenseCategory? initialCategory;

  /// Optional initial amount for a new expense.
  final double? initialAmount;

  /// Optional initial splits (userId -> amount) for a new expense.
  final Map<String, double>? initialSplits;

  /// Optional initial description for a new expense.
  final String? initialDescription;

  /// Creates an AddExpenseDialog.
  ///
  /// [group] is the group for the expense.
  /// [currentUser] is the user creating/editing.
  /// [expenseToEdit] is the expense to edit, or null for new.
  const AddExpenseDialog({
    super.key,
    required this.group,
    required this.currentUser,
    this.expenseToEdit,
    this.initialCategory,
    this.initialAmount,
    this.initialSplits,
    this.initialDescription,
  });

  @override
  State<AddExpenseDialog> createState() => _AddExpenseDialogState();
}

/// State for AddExpenseDialog.
///
/// Handles form logic, validation, image picking, split calculation, and submission.
class _AddExpenseDialogState extends State<AddExpenseDialog> {
  /// Form key for validating the expense form.
  final _formKey = GlobalKey<FormState>();

  /// Controller for the expense description field.
  final _descriptionController = TextEditingController();

  /// Controller for the expense amount field.
  final _amountController = TextEditingController();

  /// The selected date for the expense.
  late DateTime _selectedDate;

  /// The selected category for the expense.
  late ExpenseCategory _selectedCategory;

  /// The selected currency for the expense.
  late ExpenseCurrency _selectedCurrency;

  /// The user ID of the payer.
  late String _paidById;

  /// Map of userId to split amount for each participant.
  final Map<String, double> _splits = {};

  /// The selected receipt image file, if any.
  File? _receiptImage;

  /// Whether the dialog is currently submitting data.
  bool _isLoading = false;

  /// Whether the expense is split equally among participants.
  bool _splitEqually = true;

  /// Whether the existing receipt has been removed.
  bool _receiptRemoved = false;

  @override
  void initState() {
    super.initState();
    // Initialize form fields and splits based on whether editing or creating
    _selectedDate = widget.expenseToEdit?.date ?? DateTime.now();
    _selectedCategory =
        widget.expenseToEdit?.category ??
        widget.initialCategory ??
        ExpenseCategory.other;
    _selectedCurrency = widget.expenseToEdit?.currency ?? ExpenseCurrency.eur;
    _paidById = widget.expenseToEdit?.paidById ?? widget.currentUser.id;

    if (widget.expenseToEdit != null) {
      // Editing: pre-fill fields and splits
      _descriptionController.text = widget.expenseToEdit!.description;
      _amountController.text = widget.expenseToEdit!.amount.toString();
      for (final split in widget.expenseToEdit!.splits) {
        _splits[split.userId] = split.amount;
      }
      _splitEqually = false;
    } else {
      // Creating: initialize splits
      if (widget.initialDescription != null) {
        _descriptionController.text = widget.initialDescription!;
      }

      if (widget.initialAmount != null) {
        _amountController.text = widget.initialAmount.toString();
      }

      if (widget.initialSplits != null) {
        _splits.addAll(widget.initialSplits!);
        // Fill remaining members with 0 if not in initialSplits
        for (final member in widget.group.members) {
          if (!_splits.containsKey(member.userId)) {
            _splits[member.userId] = 0;
          } else {
            // If we have specific splits, we probably aren't splitting equally by default logic
            // unless we want to force it. For reimbursement, we likely set exact amounts.
            _splitEqually = false;
          }
        }
      } else {
        // Default behavior: initialize splits for all group members
        for (final member in widget.group.members) {
          _splits[member.userId] = 0;
        }
      }
    }
  }

  @override
  void dispose() {
    // Dispose controllers to free resources
    _descriptionController.dispose();
    _amountController.dispose();
    super.dispose();
  }

  /// Opens the image picker and validates the selected image (max 5MB).
  ///
  /// If valid, sets [_receiptImage] to the selected file.
  /// Shows an error message if the file is too large.
  Future<void> _pickImage() async {
    final picker = ImagePicker();
    final pickedFile = await picker.pickImage(
      source: ImageSource.gallery,
      maxWidth: 1920,
      maxHeight: 1920,
    );

    if (pickedFile != null) {
      final file = File(pickedFile.path);
      final fileSize = await file.length();

      if (fileSize > 5 * 1024 * 1024) {
        if (mounted) {
          ErrorService().showError(
            message: 'L\'image ne doit pas dépasser 5 Mo',
          );
        }
        return;
      }

      setState(() {
        _receiptImage = file;
      });
    }
  }

  /// Calculates splits for equal division among selected members.
  ///
  /// Updates [_splits] map with equal amounts for each selected participant.
  void _calculateSplits() {
    if (!_splitEqually) return;

    final amount = double.tryParse(_amountController.text) ?? 0;
    final selectedMembers = _splits.entries.where((e) => e.value >= 0).toList();

    if (selectedMembers.isEmpty) return;

    final splitAmount = amount / selectedMembers.length;

    setState(() {
      for (final entry in selectedMembers) {
        _splits[entry.key] = splitAmount;
      }
    });
  }

  /// Validates the form and submits the expense.
  ///
  /// - Checks all form fields and splits
  /// - Converts amount to EUR using exchange rates
  /// - Dispatches CreateExpense or UpdateExpense event to ExpenseBloc
  /// - Shows success or error feedback
  Future<void> _submit() async {
    if (!_formKey.currentState!.validate()) return;

    final amount = double.parse(_amountController.text);
    final selectedSplits = _splits.entries.where((e) => e.value > 0).map((e) {
      final member = widget.group.members.firstWhere((m) => m.userId == e.key);
      return ExpenseSplit(
        userId: e.key,
        userName: member.firstName,
        amount: e.value,
      );
    }).toList();

    if (selectedSplits.isEmpty) {
      ErrorService().showError(
        message: 'Veuillez sélectionner au moins un participant',
      );
      return;
    }

    setState(() => _isLoading = true);

    try {
      // Convertir en EUR
      final amountInEur = context.read<ExpenseBloc>().state is ExpensesLoaded
          ? ((context.read<ExpenseBloc>().state as ExpensesLoaded)
                        .exchangeRates[_selectedCurrency.code] ??
                    1.0) *
                amount
          : amount;

      final payer = widget.group.members.firstWhere(
        (m) => m.userId == _paidById,
      );

      final expense = Expense(
        id: widget.expenseToEdit?.id ?? '',
        groupId: widget.group.id,
        description: _descriptionController.text.trim(),
        amount: amount,
        currency: _selectedCurrency,
        amountInEur: amountInEur,
        category: _selectedCategory,
        paidById: _paidById,
        paidByName: payer.firstName,
        splits: selectedSplits,
        date: _selectedDate,
        receiptUrl: _receiptRemoved ? null : widget.expenseToEdit?.receiptUrl,
        createdAt: widget.expenseToEdit?.createdAt ?? DateTime.now(),
      );

      if (widget.expenseToEdit == null) {
        context.read<ExpenseBloc>().add(
          CreateExpense(expense: expense, receiptImage: _receiptImage),
        );
      } else {
        context.read<ExpenseBloc>().add(
          UpdateExpense(expense: expense, newReceiptImage: _receiptImage),
        );
      }

      if (mounted) {
        Navigator.of(context).pop();
        ErrorService().showSnackbar(
          message: widget.expenseToEdit == null
              ? 'Dépense ajoutée'
              : 'Dépense modifiée',
          isError: false,
        );
      }
    } catch (e) {
      if (mounted) {
        ErrorService().showError(message: 'Erreur: $e');
      }
    } finally {
      if (mounted) {
        setState(() => _isLoading = false);
      }
    }
  }

  /// Builds the dialog UI with all form fields and controls.
  ///
  /// Returns a Dialog widget containing the expense form.
  @override
  Widget build(BuildContext context) {
    final theme = Theme.of(context);
    final isDark = theme.brightness == Brightness.dark;

    return Dialog(
      shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(16)),
      backgroundColor: isDark ? theme.scaffoldBackgroundColor : Colors.white,
      insetPadding: const EdgeInsets.symmetric(horizontal: 16, vertical: 24),
      child: Container(
        constraints: const BoxConstraints(maxWidth: 500, maxHeight: 800),
        child: Column(
          children: [
            // Header
            Padding(
              padding: const EdgeInsets.fromLTRB(24, 24, 16, 16),
              child: Row(
                children: [
                  Expanded(
                    child: Text(
                      widget.expenseToEdit == null
                          ? 'Nouvelle dépense'
                          : 'Modifier la dépense',
                      style: const TextStyle(
                        fontSize: 20,
                        fontWeight: FontWeight.bold,
                      ),
                      textAlign: TextAlign.center,
                    ),
                  ),
                  IconButton(
                    icon: const Icon(Icons.close),
                    onPressed: () => Navigator.of(context).pop(),
                    padding: EdgeInsets.zero,
                    constraints: const BoxConstraints(),
                  ),
                ],
              ),
            ),
            const Divider(height: 1),

            // Form Content
            Expanded(
              child: Form(
                key: _formKey,
                child: ListView(
                  padding: const EdgeInsets.all(24),
                  children: [
                    // Description
                    TextFormField(
                      controller: _descriptionController,
                      decoration: InputDecoration(
                        labelText: 'Description',
                        hintText: 'Ex: Restaurant, Essence...',
                        prefixIcon: const Icon(Icons.description_outlined),
                        border: OutlineInputBorder(
                          borderRadius: BorderRadius.circular(8),
                        ),
                        contentPadding: const EdgeInsets.symmetric(
                          horizontal: 16,
                          vertical: 16,
                        ),
                      ),
                      validator: (value) {
                        if (value == null || value.trim().isEmpty) {
                          return 'Requis';
                        }
                        return null;
                      },
                    ),
                    const SizedBox(height: 16),

                    // Montant et Devise
                    Row(
                      crossAxisAlignment: CrossAxisAlignment.start,
                      children: [
                        Expanded(
                          flex: 2,
                          child: TextFormField(
                            controller: _amountController,
                            decoration: InputDecoration(
                              labelText: 'Montant',
                              prefixIcon: const Icon(Icons.euro_symbol),
                              border: OutlineInputBorder(
                                borderRadius: BorderRadius.circular(8),
                              ),
                              contentPadding: const EdgeInsets.symmetric(
                                horizontal: 16,
                                vertical: 16,
                              ),
                            ),
                            keyboardType: const TextInputType.numberWithOptions(
                              decimal: true,
                            ),
                            onChanged: (_) => _calculateSplits(),
                            validator: (value) {
                              if (value == null || value.isEmpty) {
                                return 'Requis';
                              }
                              if (double.tryParse(value) == null ||
                                  double.parse(value) <= 0) {
                                return 'Invalide';
                              }
                              return null;
                            },
                          ),
                        ),
                        const SizedBox(width: 12),
                        Expanded(
                          child: DropdownButtonFormField<ExpenseCurrency>(
                            initialValue: _selectedCurrency,
                            decoration: InputDecoration(
                              labelText: 'Devise',
                              border: OutlineInputBorder(
                                borderRadius: BorderRadius.circular(8),
                              ),
                              contentPadding: const EdgeInsets.symmetric(
                                horizontal: 12,
                                vertical: 16,
                              ),
                            ),
                            items: ExpenseCurrency.values.map((currency) {
                              return DropdownMenuItem(
                                value: currency,
                                child: Text(currency.code),
                              );
                            }).toList(),
                            onChanged: (value) {
                              if (value != null) {
                                setState(() => _selectedCurrency = value);
                              }
                            },
                          ),
                        ),
                      ],
                    ),
                    const SizedBox(height: 16),

                    // Catégorie
                    DropdownButtonFormField<ExpenseCategory>(
                      initialValue: _selectedCategory,
                      decoration: InputDecoration(
                        labelText: 'Catégorie',
                        prefixIcon: Icon(_selectedCategory.icon),
                        border: OutlineInputBorder(
                          borderRadius: BorderRadius.circular(8),
                        ),
                        contentPadding: const EdgeInsets.symmetric(
                          horizontal: 16,
                          vertical: 16,
                        ),
                      ),
                      items: ExpenseCategory.values.map((category) {
                        return DropdownMenuItem(
                          value: category,
                          child: Text(category.displayName),
                        );
                      }).toList(),
                      onChanged: (value) {
                        if (value != null) {
                          setState(() => _selectedCategory = value);
                        }
                      },
                    ),
                    const SizedBox(height: 16),

                    // Date
                    InkWell(
                      onTap: () async {
                        final date = await showDatePicker(
                          context: context,
                          initialDate: _selectedDate,
                          firstDate: DateTime(2020),
                          lastDate: DateTime.now().add(
                            const Duration(days: 365),
                          ),
                        );
                        if (date != null) setState(() => _selectedDate = date);
                      },
                      borderRadius: BorderRadius.circular(8),
                      child: InputDecorator(
                        decoration: InputDecoration(
                          labelText: 'Date',
                          prefixIcon: const Icon(Icons.calendar_today_outlined),
                          border: OutlineInputBorder(
                            borderRadius: BorderRadius.circular(8),
                          ),
                          contentPadding: const EdgeInsets.symmetric(
                            horizontal: 16,
                            vertical: 16,
                          ),
                        ),
                        child: Text(
                          DateFormat('dd/MM/yyyy').format(_selectedDate),
                          style: theme.textTheme.bodyLarge,
                        ),
                      ),
                    ),
                    const SizedBox(height: 16),

                    // Payé par
                    DropdownButtonFormField<String>(
                      initialValue: _paidById,
                      decoration: InputDecoration(
                        labelText: 'Payé par',
                        prefixIcon: const Icon(Icons.person_outline),
                        border: OutlineInputBorder(
                          borderRadius: BorderRadius.circular(8),
                        ),
                        contentPadding: const EdgeInsets.symmetric(
                          horizontal: 16,
                          vertical: 16,
                        ),
                      ),
                      items: widget.group.members.map((member) {
                        return DropdownMenuItem(
                          value: member.userId,
                          child: Text(member.firstName),
                        );
                      }).toList(),
                      onChanged: (value) {
                        if (value != null) setState(() => _paidById = value);
                      },
                    ),
                    const SizedBox(height: 24),

                    // Division Section
                    Container(
                      decoration: BoxDecoration(
                        color: isDark ? Colors.grey[800] : Colors.grey[50],
                        borderRadius: BorderRadius.circular(12),
                        border: Border.all(color: theme.dividerColor),
                      ),
                      padding: const EdgeInsets.all(16),
                      child: Column(
                        children: [
                          Row(
                            children: [
                              const Text(
                                'Division',
                                style: TextStyle(
                                  fontSize: 16,
                                  fontWeight: FontWeight.bold,
                                ),
                              ),
                              const Spacer(),
                              Text(
                                'Égale',
                                style: TextStyle(
                                  color: isDark
                                      ? Colors.grey[400]
                                      : Colors.grey[600],
                                ),
                              ),
                              const SizedBox(width: 8),
                              Switch(
                                value: _splitEqually,
                                onChanged: (value) {
                                  setState(() {
                                    _splitEqually = value;
                                    if (value) _calculateSplits();
                                  });
                                },
                                activeThumbColor: theme.colorScheme.primary,
                              ),
                            ],
                          ),
                          const Divider(),
                          ...widget.group.members.map((member) {
                            final isSelected =
                                _splits.containsKey(member.userId) &&
                                _splits[member.userId]! >= 0;

                            return Padding(
                              padding: const EdgeInsets.symmetric(vertical: 4),
                              child: Row(
                                children: [
                                  Expanded(
                                    child: Text(
                                      member.firstName,
                                      style: const TextStyle(fontSize: 16),
                                    ),
                                  ),
                                  if (!_splitEqually && isSelected)
                                    SizedBox(
                                      width: 100,
                                      child: TextFormField(
                                        initialValue: _splits[member.userId]
                                            ?.toStringAsFixed(2),
                                        decoration: const InputDecoration(
                                          isDense: true,
                                          contentPadding: EdgeInsets.symmetric(
                                            horizontal: 8,
                                            vertical: 8,
                                          ),
                                          border: OutlineInputBorder(),
                                          suffixText: '€',
                                        ),
                                        keyboardType:
                                            const TextInputType.numberWithOptions(
                                              decimal: true,
                                            ),
                                        onChanged: (value) {
                                          final amount =
                                              double.tryParse(value) ?? 0;
                                          setState(
                                            () =>
                                                _splits[member.userId] = amount,
                                          );
                                        },
                                      ),
                                    ),
                                  Checkbox(
                                    value: isSelected,
                                    onChanged: (value) {
                                      setState(() {
                                        if (value == true) {
                                          _splits[member.userId] = 0;
                                          if (_splitEqually) _calculateSplits();
                                        } else {
                                          _splits[member.userId] = -1;
                                        }
                                      });
                                    },
                                    activeColor: theme.colorScheme.primary,
                                    shape: RoundedRectangleBorder(
                                      borderRadius: BorderRadius.circular(4),
                                    ),
                                  ),
                                ],
                              ),
                            );
                          }),
                        ],
                      ),
                    ),
                    const SizedBox(height: 16),

                    // Reçu (Optional - keeping simple for now as per design focus)
                    if (_receiptImage != null ||
                        (widget.expenseToEdit?.receiptUrl != null &&
                            !_receiptRemoved))
                      Container(
                        padding: const EdgeInsets.all(12),
                        decoration: BoxDecoration(
                          border: Border.all(color: theme.dividerColor),
                          borderRadius: BorderRadius.circular(8),
                        ),
                        child: Row(
                          children: [
                            const Icon(Icons.receipt_long, color: Colors.green),
                            const SizedBox(width: 8),
                            const Text('Reçu joint'),
                            const Spacer(),
                            IconButton(
                              icon: const Icon(Icons.close),
                              onPressed: () => setState(() {
                                _receiptImage = null;
                                _receiptRemoved = true;
                              }),
                            ),
                          ],
                        ),
                      )
                    else
                      OutlinedButton.icon(
                        onPressed: _pickImage,
                        icon: const Icon(Icons.camera_alt_outlined),
                        label: const Text('Ajouter un reçu'),
                        style: OutlinedButton.styleFrom(
                          padding: const EdgeInsets.symmetric(vertical: 12),
                          shape: RoundedRectangleBorder(
                            borderRadius: BorderRadius.circular(8),
                          ),
                        ),
                      ),
                  ],
                ),
              ),
            ),

            // Bottom Button
            Padding(
              padding: const EdgeInsets.all(24),
              child: SizedBox(
                width: double.infinity,
                child: ElevatedButton(
                  onPressed: _isLoading ? null : _submit,
                  style: ElevatedButton.styleFrom(
                    padding: const EdgeInsets.symmetric(vertical: 16),
                    shape: RoundedRectangleBorder(
                      borderRadius: BorderRadius.circular(12),
                    ),
                    backgroundColor: theme.colorScheme.primary,
                    foregroundColor: Colors.white,
                    elevation: 0,
                  ),
                  child: _isLoading
                      ? const SizedBox(
                          height: 20,
                          width: 20,
                          child: CircularProgressIndicator(
                            strokeWidth: 2,
                            valueColor: AlwaysStoppedAnimation<Color>(
                              Colors.white,
                            ),
                          ),
                        )
                      : Text(
                          widget.expenseToEdit == null
                              ? 'Ajouter'
                              : 'Enregistrer',
                          style: const TextStyle(
                            fontSize: 16,
                            fontWeight: FontWeight.bold,
                          ),
                        ),
                ),
              ),
            ),
          ],
        ),
      ),
    );
  }
}
