import 'package:equatable/equatable.dart';
import '../../models/expense.dart';
import 'dart:io';

/// Abstract base class for all expense-related events.
/// 
/// This class extends [Equatable] to enable value equality for event comparison.
/// All expense events in the application should inherit from this class.
abstract class ExpenseEvent extends Equatable {
  /// Creates a new [ExpenseEvent].
  const ExpenseEvent();

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

/// Event to load all expenses for a specific group.
/// 
/// This event triggers the loading of all expenses associated with
/// the specified group, setting up a stream to receive real-time updates.
class LoadExpensesByGroup extends ExpenseEvent {
  /// The ID of the group to load expenses for.
  final String groupId;

  /// Creates a [LoadExpensesByGroup] event for the specified [groupId].
  const LoadExpensesByGroup(this.groupId);

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

/// Event to create a new expense.
/// 
/// This event is dispatched when a user wants to add a new expense
/// to a group, optionally including a receipt image.
class CreateExpense extends ExpenseEvent {
  /// The expense data to create.
  final Expense expense;
  
  /// Optional receipt image file to upload with the expense.
  final File? receiptImage;

  /// Creates a [CreateExpense] event with the expense data and optional receipt.
  const CreateExpense({
    required this.expense,
    this.receiptImage,
  });

  @override
  List<Object?> get props => [expense, receiptImage];
}

/// Event to update an existing expense.
/// 
/// This event is dispatched when a user modifies an existing expense,
/// optionally changing the receipt image.
class UpdateExpense extends ExpenseEvent {
  /// The updated expense data.
  final Expense expense;
  
  /// Optional new receipt image file to replace the existing one.
  final File? newReceiptImage;

  /// Creates an [UpdateExpense] event with updated expense data.
  const UpdateExpense({
    required this.expense,
    this.newReceiptImage,
  });

  @override
  List<Object?> get props => [expense, newReceiptImage];
}

/// Event to delete an expense.
/// 
/// This event is dispatched when a user wants to permanently
/// remove an expense from the group.
class DeleteExpense extends ExpenseEvent {
  /// The ID of the expense to delete.
  final String expenseId;

  /// Creates a [DeleteExpense] event for the specified [expenseId].
  const DeleteExpense(this.expenseId);

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

/// Event to mark a user's split of an expense as paid.
/// 
/// This event is used when a user has paid their portion of
/// a shared expense to the person who originally paid for it.
class MarkSplitAsPaid extends ExpenseEvent {
  /// The ID of the expense containing the split.
  final String expenseId;
  
  /// The ID of the user whose split is being marked as paid.
  final String userId;

  /// Creates a [MarkSplitAsPaid] event for the specified expense and user.
  const MarkSplitAsPaid({
    required this.expenseId,
    required this.userId,
  });

  @override
  List<Object?> get props => [expenseId, userId];
}

/// Event to archive an expense.
/// 
/// This event moves an expense to an archived state, hiding it
/// from the main expense list while preserving it for history.
class ArchiveExpense extends ExpenseEvent {
  /// The ID of the expense to archive.
  final String expenseId;

  /// Creates an [ArchiveExpense] event for the specified [expenseId].
  const ArchiveExpense(this.expenseId);

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

/// Internal event for handling expense stream updates.
/// 
/// This is a private event used internally by the bloc to handle
/// real-time updates from the Firestore stream.
class ExpensesUpdated extends ExpenseEvent {
  /// The updated list of expenses from the stream.
  final List<Expense> expenses;
  
  /// Optional error message if the stream encountered an error.
  final String? error;

  /// Creates an [ExpensesUpdated] event with the expense list and optional error.
  const ExpensesUpdated(this.expenses, {this.error});

  @override
  List<Object?> get props => [expenses, error];
}
