import 'package:bloc/bloc.dart';
import 'package:dartz/dartz.dart';
import 'package:freezed_annotation/freezed_annotation.dart';
import 'package:injectable/injectable.dart';

import '../../../domain/category/category.dart';
import '../../../domain/product/product.dart';

part 'sync_setting_event.dart';
part 'sync_setting_state.dart';
part 'sync_setting_bloc.freezed.dart';

@injectable
class SyncSettingBloc extends Bloc<SyncSettingEvent, SyncSettingState> {
  final IProductRepository _productRepository;
  final ICategoryRepository _categoryRepository;

  SyncSettingBloc(this._productRepository, this._categoryRepository)
    : super(SyncSettingState.initial()) {
    on<SyncSettingEvent>(_onSyncSettingEvent);
  }

  Future<void> _onSyncSettingEvent(
    SyncSettingEvent event,
    Emitter<SyncSettingState> emit,
  ) {
    return event.map(
      loadStats: (e) => _onLoadStats(emit),
      syncAllData: (e) => _onSyncAllData(emit),
      clearAllData: (e) => _onClearAllData(emit),
      syncProducts: (e) => _onSyncProducts(emit),
      syncCategories: (e) => _onSyncCategories(emit),
      clearCategories: (e) => _onClearCategories(emit),
      clearProducts: (e) => _onClearProducts(emit),
    );
  }

  Future<void> _onLoadStats(Emitter<SyncSettingState> emit) async {
    emit(
      state.copyWith(
        isLoading: true,
        failureOptionProduct: none(),
        failureOptionCategory: none(),
      ),
    );

    final productStats = await _productRepository.getDatabaseStats();
    final categoryStats = await _categoryRepository.getDatabaseStats();

    productStats.fold(
      (failure) {
        emit(
          state.copyWith(
            isLoading: false,
            failureOptionProduct: optionOf(failure),
          ),
        );
      },
      (data) {
        emit(
          state.copyWith(
            isLoading: false,
            productStats: data,
            failureOptionProduct: none(),
          ),
        );
      },
    );

    categoryStats.fold(
      (failure) {
        emit(
          state.copyWith(
            isLoading: false,
            failureOptionCategory: optionOf(failure),
          ),
        );
      },
      (data) {
        emit(
          state.copyWith(
            isLoading: false,
            categoryStats: data,
            failureOptionCategory: none(),
          ),
        );
      },
    );
  }

  Future<void> _onSyncAllData(Emitter<SyncSettingState> emit) async {
    emit(
      state.copyWith(
        isSyncing: true,
        failureOptionSyncCategory: none(),
        failureOptionSyncProduct: none(),
      ),
    );

    // Sync categories first
    final categoryResult = await _categoryRepository.syncAllCategories();

    bool categorySuccess = false;
    categoryResult.fold(
      (failure) {
        emit(
          state.copyWith(failureOptionSyncCategory: optionOf(left(failure))),
        );
      },
      (success) {
        categorySuccess = true;
        emit(
          state.copyWith(failureOptionSyncCategory: optionOf(right(success))),
        );
      },
    );

    // Only sync products if categories synced successfully
    if (categorySuccess) {
      final productResult = await _productRepository.syncAllProducts();

      productResult.fold(
        (failure) {
          emit(
            state.copyWith(
              isSyncing: false,
              failureOptionSyncProduct: optionOf(left(failure)),
            ),
          );
        },
        (success) {
          emit(
            state.copyWith(
              isSyncing: false,
              failureOptionSyncProduct: optionOf(right(success)),
            ),
          );
        },
      );
    } else {
      emit(state.copyWith(isSyncing: false));
    }

    // Reload stats after sync
    add(const SyncSettingEvent.loadStats());
  }

  Future<void> _onClearAllData(Emitter<SyncSettingState> emit) async {
    emit(state.copyWith(isLoading: true));

    try {
      // Clear products and categories
      await _productRepository.clearAllProducts();
      await _categoryRepository.clearAllCategories();

      // Clear caches
      _productRepository.clearCache();
      _categoryRepository.clearCache();

      emit(state.copyWith(isLoading: false));

      // Reload stats after clearing
      add(const SyncSettingEvent.loadStats());
    } catch (e) {
      emit(state.copyWith(isLoading: false));
    }
  }

  Future<void> _onSyncProducts(Emitter<SyncSettingState> emit) async {
    emit(state.copyWith(isLoading: true, failureOptionSyncProduct: none()));

    final result = await _productRepository.syncAllProducts();

    result.fold(
      (failure) {
        emit(
          state.copyWith(
            isLoading: false,
            failureOptionSyncProduct: optionOf(left(failure)),
          ),
        );
      },
      (success) {
        emit(
          state.copyWith(
            isLoading: false,
            failureOptionSyncProduct: optionOf(right(success)),
          ),
        );
      },
    );

    // Reload stats after sync
    add(const SyncSettingEvent.loadStats());
  }

  Future<void> _onSyncCategories(Emitter<SyncSettingState> emit) async {
    emit(state.copyWith(isLoading: true, failureOptionSyncCategory: none()));

    final result = await _categoryRepository.syncAllCategories();

    result.fold(
      (failure) {
        emit(
          state.copyWith(
            isLoading: false,
            failureOptionSyncCategory: optionOf(left(failure)),
          ),
        );
      },
      (success) {
        emit(
          state.copyWith(
            isLoading: false,
            failureOptionSyncCategory: optionOf(right(success)),
          ),
        );
      },
    );

    // Reload stats after sync
    add(const SyncSettingEvent.loadStats());
  }

  Future<void> _onClearCategories(Emitter<SyncSettingState> emit) async {
    await _categoryRepository.clearAllCategories();
    _categoryRepository.clearCache();
  }

  Future<void> _onClearProducts(Emitter<SyncSettingState> emit) async {
    await _productRepository.clearAllProducts();
    _productRepository.clearCache();
  }
}
