import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:equatable/equatable.dart';
import 'package:flutter/material.dart';
import 'expense_split.dart';

enum ExpenseCurrency {
  eur('€', 'EUR'),
  usd('\$', 'USD'),
  gbp('£', 'GBP');

  const ExpenseCurrency(this.symbol, this.code);
  final String symbol;
  final String code;
}

enum ExpenseCategory {
  restaurant('Restaurant', Icons.restaurant),
  transport('Transport', Icons.directions_car),
  accommodation('Hébergement', Icons.hotel),
  entertainment('Loisirs', Icons.local_activity),
  shopping('Shopping', Icons.shopping_bag),
  other('Autre', Icons.category);

  const ExpenseCategory(this.displayName, this.icon);
  final String displayName;
  final IconData icon;
}

class Expense extends Equatable {
  final String id;
  final String groupId;
  final String description;
  final double amount;
  final ExpenseCurrency currency;
  final double amountInEur; // Montant converti en EUR
  final ExpenseCategory category;
  final String paidById;
  final String paidByName;
  final DateTime date;
  final DateTime createdAt;
  final DateTime? editedAt;
  final bool isEdited;
  final bool isArchived;
  final String? receiptUrl;
  final List<ExpenseSplit> splits;

  const Expense({
    required this.id,
    required this.groupId,
    required this.description,
    required this.amount,
    required this.currency,
    required this.amountInEur,
    required this.category,
    required this.paidById,
    required this.paidByName,
    required this.date,
    required this.createdAt,
    this.editedAt,
    this.isEdited = false,
    this.isArchived = false,
    this.receiptUrl,
    required this.splits,
  });

  factory Expense.fromMap(Map<String, dynamic> map, String id) {
    return Expense(
      id: id,
      groupId: map['groupId'] ?? '',
      description: map['description'] ?? '',
      amount: (map['amount'] as num?)?.toDouble() ?? 0.0,
      currency: ExpenseCurrency.values.firstWhere(
        (c) => c.code == map['currency'],
        orElse: () => ExpenseCurrency.eur,
      ),
      amountInEur: (map['amountInEur'] as num?)?.toDouble() ?? 0.0,
      category: ExpenseCategory.values.firstWhere(
        (c) => c.name == map['category'],
        orElse: () => ExpenseCategory.other,
      ),
      paidById: map['paidById'] ?? '',
      paidByName: map['paidByName'] ?? '',
      date: _parseDateTime(map['date']),
      createdAt: _parseDateTime(map['createdAt']),
      editedAt: map['editedAt'] != null ? _parseDateTime(map['editedAt']) : null,
      isEdited: map['isEdited'] ?? false,
      isArchived: map['isArchived'] ?? false,
      receiptUrl: map['receiptUrl'],
      splits: (map['splits'] as List?)
          ?.map((s) => ExpenseSplit.fromMap(s))
          .toList() ?? [],
    );
  }

  Map<String, dynamic> toMap() {
    return {
      'groupId': groupId,
      'description': description,
      'amount': amount,
      'currency': currency.code,
      'amountInEur': amountInEur,
      'category': category.name,
      'paidById': paidById,
      'paidByName': paidByName,
      'date': Timestamp.fromDate(date),
      'createdAt': Timestamp.fromDate(createdAt),
      'editedAt': editedAt != null ? Timestamp.fromDate(editedAt!) : null,
      'isEdited': isEdited,
      'isArchived': isArchived,
      'receiptUrl': receiptUrl,
      'splits': splits.map((s) => s.toMap()).toList(),
    };
  }

  static DateTime _parseDateTime(dynamic value) {
    if (value is Timestamp) return value.toDate();
    if (value is String) return DateTime.parse(value);
    if (value is DateTime) return value;
    return DateTime.now();
  }

  Expense copyWith({
    String? id,
    String? groupId,
    String? description,
    double? amount,
    ExpenseCurrency? currency,
    double? amountInEur,
    ExpenseCategory? category,
    String? paidById,
    String? paidByName,
    DateTime? date,
    DateTime? createdAt,
    DateTime? editedAt,
    bool? isEdited,
    bool? isArchived,
    String? receiptUrl,
    List<ExpenseSplit>? splits,
  }) {
    return Expense(
      id: id ?? this.id,
      groupId: groupId ?? this.groupId,
      description: description ?? this.description,
      amount: amount ?? this.amount,
      currency: currency ?? this.currency,
      amountInEur: amountInEur ?? this.amountInEur,
      category: category ?? this.category,
      paidById: paidById ?? this.paidById,
      paidByName: paidByName ?? this.paidByName,
      date: date ?? this.date,
      createdAt: createdAt ?? this.createdAt,
      editedAt: editedAt ?? this.editedAt,
      isEdited: isEdited ?? this.isEdited,
      isArchived: isArchived ?? this.isArchived,
      receiptUrl: receiptUrl ?? this.receiptUrl,
      splits: splits ?? this.splits,
    );
  }

  Expense copyWithEdit({
    String? description,
    double? amount,
    ExpenseCurrency? currency,
    double? amountInEur,
    ExpenseCategory? category,
    List<ExpenseSplit>? splits,
    String? receiptUrl,
  }) {
    return copyWith(
      description: description,
      amount: amount,
      currency: currency,
      amountInEur: amountInEur,
      category: category,
      splits: splits,
      receiptUrl: receiptUrl,
      editedAt: DateTime.now(),
      isEdited: true,
    );
  }

  // Marquer comme archivé
  Expense copyWithArchived() {
    return copyWith(
      isArchived: true,
    );
  }

  // Ajouter/mettre à jour l'URL du reçu
  Expense copyWithReceipt(String receiptUrl) {
    return copyWith(
      receiptUrl: receiptUrl,
    );
  }

  // Mettre à jour les splits
  Expense copyWithSplits(List<ExpenseSplit> newSplits) {
    return copyWith(
      splits: newSplits,
    );
  }

  @override
  List<Object?> get props => [id];
}