/// BLoC pour la gestion des budgets
library budget_bloc;

import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:injectable/injectable.dart';
import '../../domain/usecases/get_budgets.dart';
import '../../domain/usecases/get_budget_by_id.dart';
import '../../domain/usecases/create_budget.dart';
import '../../domain/usecases/get_budget_tracking.dart';
import 'budget_event.dart';
import 'budget_state.dart';

@injectable
class BudgetBloc extends Bloc<BudgetEvent, BudgetState> {
  final GetBudgets getBudgets;
  final GetBudgetById getBudgetById;
  final CreateBudget createBudget;
  final GetBudgetTracking getBudgetTracking;

  BudgetBloc({
    required this.getBudgets,
    required this.getBudgetById,
    required this.createBudget,
    required this.getBudgetTracking,
  }) : super(const BudgetInitial()) {
    on<LoadBudgets>(_onLoadBudgets);
    on<LoadBudgetById>(_onLoadBudgetById);
    on<CreateBudgetEvent>(_onCreateBudget);
    on<LoadBudgetTracking>(_onLoadBudgetTracking);
    on<RefreshBudgets>(_onRefreshBudgets);
    on<FilterBudgets>(_onFilterBudgets);
  }

  Future<void> _onLoadBudgets(
    LoadBudgets event,
    Emitter<BudgetState> emit,
  ) async {
    emit(const BudgetsLoading());

    final result = await getBudgets(
      organizationId: event.organizationId,
      status: event.status,
      year: event.year,
    );

    result.fold(
      (failure) => emit(BudgetError(failure.message)),
      (budgets) {
        if (budgets.isEmpty) {
          emit(const BudgetsEmpty());
        } else {
          emit(BudgetsLoaded(
            budgets: budgets,
            filterStatus: event.status,
            filterYear: event.year,
          ));
        }
      },
    );
  }

  Future<void> _onLoadBudgetById(
    LoadBudgetById event,
    Emitter<BudgetState> emit,
  ) async {
    emit(const BudgetsLoading());

    final result = await getBudgetById(event.budgetId);

    result.fold(
      (failure) => emit(BudgetError(failure.message)),
      (budget) => emit(BudgetDetailLoaded(budget)),
    );
  }

  Future<void> _onCreateBudget(
    CreateBudgetEvent event,
    Emitter<BudgetState> emit,
  ) async {
    emit(const BudgetActionInProgress('create'));

    final result = await createBudget(
      name: event.name,
      description: event.description,
      organizationId: event.organizationId,
      period: event.period,
      year: event.year,
      month: event.month,
      lines: event.lines,
    );

    result.fold(
      (failure) => emit(BudgetError(failure.message)),
      (budget) => emit(BudgetCreated(budget: budget)),
    );
  }

  Future<void> _onLoadBudgetTracking(
    LoadBudgetTracking event,
    Emitter<BudgetState> emit,
  ) async {
    emit(const BudgetsLoading());

    // Load budget first
    final budgetResult = await getBudgetById(event.budgetId);

    await budgetResult.fold(
      (failure) async => emit(BudgetError(failure.message)),
      (budget) async {
        // Then load tracking
        final trackingResult = await getBudgetTracking(budgetId: event.budgetId);

        trackingResult.fold(
          (failure) => emit(BudgetError(failure.message)),
          (tracking) => emit(BudgetTrackingLoaded(
            budget: budget,
            tracking: tracking,
          )),
        );
      },
    );
  }

  Future<void> _onRefreshBudgets(
    RefreshBudgets event,
    Emitter<BudgetState> emit,
  ) async {
    final result = await getBudgets(
      organizationId: event.organizationId,
      status: event.status,
      year: event.year,
    );

    result.fold(
      (failure) => emit(BudgetError(failure.message)),
      (budgets) {
        if (budgets.isEmpty) {
          emit(const BudgetsEmpty());
        } else {
          emit(BudgetsLoaded(
            budgets: budgets,
            filterStatus: event.status,
            filterYear: event.year,
          ));
        }
      },
    );
  }

  Future<void> _onFilterBudgets(
    FilterBudgets event,
    Emitter<BudgetState> emit,
  ) async {
    // Keep current organization if in loaded state
    String? organizationId;
    if (state is BudgetsLoaded) {
      final currentState = state as BudgetsLoaded;
      // Extract org ID from first budget if available
      if (currentState.budgets.isNotEmpty) {
        organizationId = currentState.budgets.first.organizationId;
      }
    }

    emit(const BudgetsLoading());

    final result = await getBudgets(
      organizationId: organizationId,
      status: event.status,
      year: event.year,
    );

    result.fold(
      (failure) => emit(BudgetError(failure.message)),
      (budgets) {
        if (budgets.isEmpty) {
          emit(const BudgetsEmpty());
        } else {
          emit(BudgetsLoaded(
            budgets: budgets,
            filterStatus: event.status,
            filterYear: event.year,
          ));
        }
      },
    );
  }
}
