/// BLoC pour le sélecteur d'organisation multi-org.
///
/// Charge GET /api/membres/mes-organisations et maintient
/// l'organisation active via [OrgContextService].
library org_switcher_bloc;

import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:equatable/equatable.dart';
import 'package:injectable/injectable.dart';
import 'package:dio/dio.dart';
import '../../../core/network/api_client.dart';
import '../../../core/network/org_context_service.dart';
import '../../../core/utils/logger.dart';
import '../data/models/org_switcher_entry.dart';

// ─── ÉVÉNEMENTS ─────────────────────────────────────────────────────────────

abstract class OrgSwitcherEvent extends Equatable {
  const OrgSwitcherEvent();
  @override
  List<Object?> get props => [];
}

/// Charge la liste des organisations du membre connecté.
class OrgSwitcherLoadRequested extends OrgSwitcherEvent {
  const OrgSwitcherLoadRequested();
}

/// Sélectionne une organisation comme active.
class OrgSwitcherSelectRequested extends OrgSwitcherEvent {
  final OrgSwitcherEntry organisation;
  const OrgSwitcherSelectRequested(this.organisation);
  @override
  List<Object?> get props => [organisation];
}

// ─── ÉTATS ──────────────────────────────────────────────────────────────────

abstract class OrgSwitcherState extends Equatable {
  const OrgSwitcherState();
  @override
  List<Object?> get props => [];
}

class OrgSwitcherInitial extends OrgSwitcherState {}

class OrgSwitcherLoading extends OrgSwitcherState {}

class OrgSwitcherLoaded extends OrgSwitcherState {
  final List<OrgSwitcherEntry> organisations;
  final OrgSwitcherEntry? active;

  const OrgSwitcherLoaded({required this.organisations, this.active});

  OrgSwitcherLoaded copyWith({
    List<OrgSwitcherEntry>? organisations,
    OrgSwitcherEntry? active,
  }) {
    return OrgSwitcherLoaded(
      organisations: organisations ?? this.organisations,
      active: active ?? this.active,
    );
  }

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

class OrgSwitcherError extends OrgSwitcherState {
  final String message;
  const OrgSwitcherError(this.message);
  @override
  List<Object?> get props => [message];
}

// ─── BLOC ────────────────────────────────────────────────────────────────────

@injectable
class OrgSwitcherBloc extends Bloc<OrgSwitcherEvent, OrgSwitcherState> {
  final ApiClient _apiClient;
  final OrgContextService _orgContextService;

  static const String _endpoint = '/api/membres/mes-organisations';

  OrgSwitcherBloc(this._apiClient, this._orgContextService)
      : super(OrgSwitcherInitial()) {
    on<OrgSwitcherLoadRequested>(_onLoad);
    on<OrgSwitcherSelectRequested>(_onSelect);
  }

  Future<void> _onLoad(
    OrgSwitcherLoadRequested event,
    Emitter<OrgSwitcherState> emit,
  ) async {
    emit(OrgSwitcherLoading());
    try {
      final response = await _apiClient.get<List<dynamic>>(_endpoint);
      final rawList = response.data as List<dynamic>? ?? [];
      final orgs = rawList
          .map((e) => OrgSwitcherEntry.fromJson(e as Map<String, dynamic>))
          .toList();

      // Auto-select si une seule organisation ou si une org est déjà active
      OrgSwitcherEntry? active;
      if (_orgContextService.hasContext) {
        active = orgs.where((o) => o.organisationId == _orgContextService.activeOrganisationId).firstOrNull;
      }
      active ??= orgs.isNotEmpty ? orgs.first : null;

      if (active != null && !_orgContextService.hasContext) {
        _applyActiveOrg(active);
      }

      emit(OrgSwitcherLoaded(organisations: orgs, active: active));
    } on DioException catch (e) {
      AppLogger.warning('OrgSwitcherBloc: erreur réseau: ${e.message}');
      emit(OrgSwitcherError('Impossible de charger vos organisations: ${e.message}'));
    } catch (e) {
      AppLogger.error('OrgSwitcherBloc: erreur inattendue: $e');
      emit(OrgSwitcherError('Erreur inattendue: $e'));
    }
  }

  Future<void> _onSelect(
    OrgSwitcherSelectRequested event,
    Emitter<OrgSwitcherState> emit,
  ) async {
    final current = state;
    if (current is! OrgSwitcherLoaded) return;

    _applyActiveOrg(event.organisation);
    emit(current.copyWith(active: event.organisation));
    AppLogger.info('OrgSwitcherBloc: sélection → ${event.organisation.nom}');
  }

  void _applyActiveOrg(OrgSwitcherEntry org) {
    _orgContextService.setActiveOrganisation(
      organisationId: org.organisationId,
      nom: org.nom,
      type: org.typeOrganisation,
      modulesActifsCsv: org.modulesActifs,
    );
  }
}
