import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:equatable/equatable.dart';
import 'package:injectable/injectable.dart';
import '../data/datasources/souscription_datasource.dart';
import '../data/models/formule_model.dart';
import '../data/models/souscription_status_model.dart';
import '../../../../core/utils/logger.dart';

// ─────────────────────────────────────────────────────────────── Events ──────

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

/// Démarre le workflow (charge les formules + état courant si souscription existante)
class OnboardingStarted extends OnboardingEvent {
  final String? existingSouscriptionId;
  final String initialState; // NO_SUBSCRIPTION | AWAITING_PAYMENT | PAYMENT_INITIATED | AWAITING_VALIDATION | VALIDATED
  final String? typeOrganisation;
  final String? organisationId;
  const OnboardingStarted({
    required this.initialState,
    this.existingSouscriptionId,
    this.typeOrganisation,
    this.organisationId,
  });
  @override
  List<Object?> get props => [initialState, existingSouscriptionId, typeOrganisation, organisationId];
}

/// L'utilisateur a sélectionné une formule et une plage
class OnboardingFormuleSelected extends OnboardingEvent {
  final String codeFormule;
  final String plage;
  const OnboardingFormuleSelected({required this.codeFormule, required this.plage});
  @override
  List<Object?> get props => [codeFormule, plage];
}

/// L'utilisateur a sélectionné la période et le type d'organisation
class OnboardingPeriodeSelected extends OnboardingEvent {
  final String typePeriode;
  final String typeOrganisation;
  final String organisationId;
  const OnboardingPeriodeSelected({
    required this.typePeriode,
    required this.typeOrganisation,
    required this.organisationId,
  });
  @override
  List<Object?> get props => [typePeriode, typeOrganisation, organisationId];
}

/// Confirme la demande et crée la souscription en base
class OnboardingDemandeConfirmee extends OnboardingEvent {
  const OnboardingDemandeConfirmee();
}

/// Ouvre l'écran de choix du moyen de paiement (depuis le récapitulatif)
class OnboardingChoixPaiementOuvert extends OnboardingEvent {
  const OnboardingChoixPaiementOuvert();
}

/// Initie le paiement Wave
class OnboardingPaiementInitie extends OnboardingEvent {
  const OnboardingPaiementInitie();
}

/// L'utilisateur est revenu dans l'app après le paiement Wave
class OnboardingRetourDepuisWave extends OnboardingEvent {
  const OnboardingRetourDepuisWave();
}

// ─────────────────────────────────────────────────────────────── States ──────

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

class OnboardingInitial extends OnboardingState {}
class OnboardingLoading extends OnboardingState {}

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

/// Étape 1 : choix formule + plage (affiche la grille des formules)
class OnboardingStepFormule extends OnboardingState {
  final List<FormuleModel> formules;
  const OnboardingStepFormule(this.formules);
  @override
  List<Object?> get props => [formules];
}

/// Étape 2 : choix période + type organisation (formule/plage déjà sélectionnés)
class OnboardingStepPeriode extends OnboardingState {
  final String codeFormule;
  final String plage;
  final List<FormuleModel> formules;
  const OnboardingStepPeriode({
    required this.codeFormule,
    required this.plage,
    required this.formules,
  });
  @override
  List<Object?> get props => [codeFormule, plage, formules];
}

/// Étape 3 : récapitulatif avec montant calculé (avant paiement)
class OnboardingStepSummary extends OnboardingState {
  final SouscriptionStatusModel souscription;
  const OnboardingStepSummary(this.souscription);
  @override
  List<Object?> get props => [souscription];
}

/// Étape 3b : choix du moyen de paiement (Wave, Orange Money, etc.)
class OnboardingStepChoixPaiement extends OnboardingState {
  final SouscriptionStatusModel souscription;
  const OnboardingStepChoixPaiement(this.souscription);
  @override
  List<Object?> get props => [souscription];
}

/// Étape 4 : paiement Wave — URL à ouvrir dans le navigateur
class OnboardingStepPaiement extends OnboardingState {
  final SouscriptionStatusModel souscription;
  final String waveLaunchUrl;
  const OnboardingStepPaiement({required this.souscription, required this.waveLaunchUrl});
  @override
  List<Object?> get props => [souscription, waveLaunchUrl];
}

/// Paiement confirmé — déclenche un re-check du statut du compte
class OnboardingPaiementConfirme extends OnboardingState {}

/// Erreur de confirmation paiement — l'utilisateur peut réessayer
class OnboardingPaiementEchoue extends OnboardingState {
  final String message;
  final SouscriptionStatusModel souscription;
  final String waveLaunchUrl;
  const OnboardingPaiementEchoue({
    required this.message,
    required this.souscription,
    required this.waveLaunchUrl,
  });
  @override
  List<Object?> get props => [message, souscription, waveLaunchUrl];
}

/// Étape 5 : en attente d'activation (paiement reçu, activation en cours)
class OnboardingStepAttente extends OnboardingState {
  final SouscriptionStatusModel? souscription;
  const OnboardingStepAttente({this.souscription});
  @override
  List<Object?> get props => [souscription];
}

/// Souscription rejetée par le SuperAdmin
class OnboardingRejected extends OnboardingState {
  final String? commentaire;
  const OnboardingRejected({this.commentaire});
  @override
  List<Object?> get props => [commentaire];
}

// ─────────────────────────────────────────────────────────────── BLoC ────────

@injectable
class OnboardingBloc extends Bloc<OnboardingEvent, OnboardingState> {
  final SouscriptionDatasource _datasource;

  // Données accumulées au fil du wizard
  List<FormuleModel> _formules = [];
  String? _codeFormule;
  String? _plage;
  String? _typePeriode;
  String _typeOrganisation = '';
  String? _organisationId;
  SouscriptionStatusModel? _souscription;

  OnboardingBloc(this._datasource) : super(OnboardingInitial()) {
    on<OnboardingStarted>(_onStarted);
    on<OnboardingFormuleSelected>(_onFormuleSelected);
    on<OnboardingPeriodeSelected>(_onPeriodeSelected);
    on<OnboardingDemandeConfirmee>(_onDemandeConfirmee);
    on<OnboardingChoixPaiementOuvert>(_onChoixPaiementOuvert);
    on<OnboardingPaiementInitie>(_onPaiementInitie);
    on<OnboardingRetourDepuisWave>(_onRetourDepuisWave);
  }

  Future<void> _onStarted(OnboardingStarted event, Emitter<OnboardingState> emit) async {
    emit(OnboardingLoading());
    if (event.typeOrganisation != null && event.typeOrganisation!.isNotEmpty) {
      _typeOrganisation = event.typeOrganisation!;
    }
    if (event.organisationId != null && event.organisationId!.isNotEmpty) {
      _organisationId = event.organisationId;
    }
    try {
      _formules = await _datasource.getFormules();

      switch (event.initialState) {
        case 'NO_SUBSCRIPTION':
          emit(OnboardingStepFormule(_formules));

        case 'AWAITING_PAYMENT':
          final sosc = await _datasource.getMaSouscription();
          if (sosc != null) {
            _souscription = sosc;
            emit(OnboardingStepSummary(sosc));
          } else {
            emit(OnboardingStepFormule(_formules));
          }

        case 'PAYMENT_INITIATED':
          final sosc = await _datasource.getMaSouscription();
          if (sosc != null && sosc.waveLaunchUrl != null) {
            _souscription = sosc;
            emit(OnboardingStepPaiement(
              souscription: sosc,
              waveLaunchUrl: sosc.waveLaunchUrl!,
            ));
          } else {
            emit(OnboardingStepAttente(souscription: sosc));
          }

        case 'AWAITING_VALIDATION':
          final soscAwait = await _datasource.getMaSouscription();
          _souscription = soscAwait;
          emit(OnboardingStepAttente(souscription: soscAwait));

        case 'VALIDATED':
          // Paiement confirmé, souscription validée, mais activation pas encore effective
          // (edge case : auth_bloc a déjà tenté un refresh sans succès).
          // Afficher la page d'attente avec polling 15s (AwaitingValidationPage).
          final soscValidated = await _datasource.getMaSouscription();
          _souscription = soscValidated;
          emit(OnboardingStepAttente(souscription: soscValidated));

        case 'REJECTED':
          final sosc = await _datasource.getMaSouscription();
          emit(OnboardingRejected(commentaire: sosc?.statutValidation));

        default:
          emit(OnboardingStepFormule(_formules));
      }
    } catch (e) {
      AppLogger.error('OnboardingBloc._onStarted: $e');
      emit(const OnboardingError('Impossible de charger les formules. Vérifiez votre connexion.'));
    }
  }

  void _onFormuleSelected(OnboardingFormuleSelected event, Emitter<OnboardingState> emit) {
    _codeFormule = event.codeFormule;
    _plage = event.plage;
    emit(OnboardingStepPeriode(
      codeFormule: event.codeFormule,
      plage: event.plage,
      formules: _formules,
    ));
  }

  void _onPeriodeSelected(OnboardingPeriodeSelected event, Emitter<OnboardingState> emit) {
    _typePeriode = event.typePeriode;
    // typeOrganisation already set from OnboardingStarted; override only if event provides one
    if (event.typeOrganisation.isNotEmpty) {
      _typeOrganisation = event.typeOrganisation;
    }
    _organisationId = event.organisationId;
  }

  void _onChoixPaiementOuvert(OnboardingChoixPaiementOuvert event, Emitter<OnboardingState> emit) {
    if (_souscription != null) {
      emit(OnboardingStepChoixPaiement(_souscription!));
    }
  }

  Future<void> _onDemandeConfirmee(
      OnboardingDemandeConfirmee event, Emitter<OnboardingState> emit) async {
    if (_codeFormule == null || _plage == null || _typePeriode == null ||
        _organisationId == null) {
      emit(const OnboardingError('Données manquantes. Recommencez depuis le début.'));
      return;
    }
    emit(OnboardingLoading());
    try {
      final sosc = await _datasource.creerDemande(
        typeFormule: _codeFormule!,
        plageMembres: _plage!,
        typePeriode: _typePeriode!,
        typeOrganisation: _typeOrganisation.isNotEmpty ? _typeOrganisation : null,
        organisationId: _organisationId!,
      );
      if (sosc != null) {
        _souscription = sosc;
        emit(OnboardingStepSummary(sosc));
      } else {
        emit(const OnboardingError('Erreur lors de la création de la demande.'));
      }
    } catch (e) {
      emit(OnboardingError('Erreur: $e'));
    }
  }

  Future<void> _onPaiementInitie(
      OnboardingPaiementInitie event, Emitter<OnboardingState> emit) async {
    final souscId = _souscription?.souscriptionId;
    if (souscId == null) {
      emit(const OnboardingError('Souscription introuvable.'));
      return;
    }
    emit(OnboardingLoading());
    try {
      final updated = await _datasource.initierPaiement(souscId);
      if (updated?.waveLaunchUrl != null) {
        _souscription = updated;
        emit(OnboardingStepPaiement(
          souscription: updated!,
          waveLaunchUrl: updated.waveLaunchUrl!,
        ));
      } else {
        emit(const OnboardingError('Impossible d\'initier le paiement Wave.'));
      }
    } catch (e) {
      emit(OnboardingError('Erreur paiement: $e'));
    }
  }

  Future<void> _onRetourDepuisWave(
      OnboardingRetourDepuisWave event, Emitter<OnboardingState> emit) async {
    emit(OnboardingLoading());
    final souscId = _souscription?.souscriptionId;
    final waveUrl = _souscription?.waveLaunchUrl;

    if (souscId == null) {
      emit(const OnboardingError('Souscription introuvable.'));
      return;
    }

    try {
      final success = await _datasource.confirmerPaiement(souscId);
      if (success) {
        emit(OnboardingPaiementConfirme());
      } else {
        // La confirmation a échoué côté backend — l'utilisateur doit réessayer
        emit(OnboardingPaiementEchoue(
          message: 'Le paiement n\'a pas pu être confirmé. Vérifiez que le paiement Wave a bien été effectué et réessayez.',
          souscription: _souscription!,
          waveLaunchUrl: waveUrl ?? '',
        ));
      }
    } catch (e) {
      emit(OnboardingPaiementEchoue(
        message: 'Erreur lors de la confirmation: ${e.toString().replaceFirst("Exception: ", "")}',
        souscription: _souscription!,
        waveLaunchUrl: waveUrl ?? '',
      ));
    }
  }
}
