import 'dart:async';
import 'dart:developer';
import 'package:bloc/bloc.dart';
import 'package:enaklo_pos/data/datasources/product/product_local_datasource.dart';
import 'package:enaklo_pos/data/datasources/category/category_local_datasource.dart';
import 'package:enaklo_pos/data/repositories/category/category_repository.dart';
import 'package:freezed_annotation/freezed_annotation.dart';
import '../../../data/datasources/product_remote_datasource.dart';

part 'data_sync_event.dart';
part 'data_sync_state.dart';
part 'data_sync_bloc.freezed.dart';

enum SyncStep { categories, products, variants, completed }

class SyncStats {
  final int totalProducts;
  final int totalCategories;
  final int totalVariants;
  final double databaseSizeMB;

  SyncStats({
    required this.totalProducts,
    required this.totalCategories,
    required this.totalVariants,
    required this.databaseSizeMB,
  });
}

class DataSyncBloc extends Bloc<DataSyncEvent, DataSyncState> {
  final ProductRemoteDatasource _productRemoteDatasource =
      ProductRemoteDatasource();
  final ProductLocalDatasource _productLocalDatasource =
      ProductLocalDatasource.instance;
  final CategoryLocalDatasource _categoryLocalDatasource =
      CategoryLocalDatasource.instance;
  final CategoryRepository _categoryRepository = CategoryRepository.instance;

  Timer? _progressTimer;
  bool _isCancelled = false;

  DataSyncBloc() : super(const DataSyncState.initial()) {
    on<_StartSync>(_onStartSync);
    on<_CancelSync>(_onCancelSync);
  }

  @override
  Future<void> close() {
    _progressTimer?.cancel();
    return super.close();
  }

  Future<void> _onStartSync(
    _StartSync event,
    Emitter<DataSyncState> emit,
  ) async {
    log('🔄 Starting full data sync (categories + products)...');
    _isCancelled = false;

    try {
      // Step 1: Clear existing local data
      emit(const DataSyncState.syncing(
          SyncStep.categories, 0.05, 'Membersihkan data lama...'));

      await _productLocalDatasource.clearAllProducts();
      await _categoryLocalDatasource.clearAllCategories();

      if (_isCancelled) return;

      // Step 2: Sync categories first (products depend on categories)
      await _syncCategories(emit);

      if (_isCancelled) return;

      // Step 3: Sync products
      await _syncProducts(emit);

      if (_isCancelled) return;

      // Step 4: Generate final stats
      emit(const DataSyncState.syncing(
          SyncStep.completed, 0.95, 'Menyelesaikan sinkronisasi...'));

      final stats = await _generateSyncStats();

      emit(DataSyncState.completed(stats));
      log('✅ Full sync completed successfully');
    } catch (e) {
      log('❌ Sync failed: $e');
      emit(DataSyncState.error('Gagal sinkronisasi: $e'));
    }
  }

  Future<void> _syncCategories(Emitter<DataSyncState> emit) async {
    log('📁 Syncing categories...');

    emit(const DataSyncState.syncing(
      SyncStep.categories,
      0.1,
      'Mengunduh kategori...',
    ));

    try {
      // Use CategoryRepository sync method
      final result = await _categoryRepository.syncAllCategories();

      await result.fold(
        (failure) async {
          throw Exception('Gagal sync kategori: $failure');
        },
        (successMessage) async {
          log('✅ Categories sync completed: $successMessage');
          emit(const DataSyncState.syncing(
            SyncStep.categories,
            0.2,
            'Kategori berhasil diunduh',
          ));
        },
      );
    } catch (e) {
      log('❌ Category sync failed: $e');
      throw Exception('Gagal sync kategori: $e');
    }
  }

  Future<void> _syncProducts(Emitter<DataSyncState> emit) async {
    log('📦 Syncing products...');

    int page = 1;
    int totalSynced = 0;
    int? totalCount;
    int? totalPages;
    bool shouldContinue = true;

    while (!_isCancelled && shouldContinue) {
      // Calculate accurate progress (categories = 0.2, products = 0.2-0.9)
      double progress = 0.2;
      if (totalCount != null && (totalCount ?? 0) > 0) {
        progress = 0.2 + (totalSynced / (totalCount ?? 0)) * 0.7;
      }

      emit(DataSyncState.syncing(
        SyncStep.products,
        progress,
        totalCount != null
            ? 'Mengunduh produk... ($totalSynced dari $totalCount)'
            : 'Mengunduh produk... ($totalSynced produk)',
      ));

      final result = await _productRemoteDatasource.getProducts(
        page: page,
        limit: 50, // Bigger batch for sync
      );

      await result.fold(
        (failure) async {
          throw Exception(failure);
        },
        (response) async {
          final products = response.data?.products ?? [];
          final responseData = response.data;

          // Get pagination info from first response
          if (page == 1 && responseData != null) {
            totalCount = responseData.totalCount;
            totalPages = responseData.totalPages;
            log('📊 Total products to sync: $totalCount (${totalPages} pages)');
          }

          if (products.isEmpty) {
            shouldContinue = false;
            return;
          }

          // Save to local database in batches
          await _productLocalDatasource.saveProductsBatch(products);

          totalSynced += products.length;
          page++;

          log('📦 Synced page ${page - 1}: ${products.length} products (Total: $totalSynced)');

          // Check if we reached the end using pagination info
          if (totalPages != null && page > (totalPages ?? 0)) {
            shouldContinue = false;
            return;
          }

          // Fallback check if pagination info not available
          if (products.length < 50) {
            shouldContinue = false;
            return;
          }

          // Small delay to prevent overwhelming the server
          await Future.delayed(Duration(milliseconds: 100));
        },
      );
    }

    emit(DataSyncState.syncing(
      SyncStep.products,
      0.9,
      'Produk berhasil diunduh ($totalSynced dari ${totalCount ?? totalSynced})',
    ));

    log('✅ Products sync completed: $totalSynced products synced');
  }

  Future<SyncStats> _generateSyncStats() async {
    final productStats = await _productLocalDatasource.getDatabaseStats();
    final categoryStats = await _categoryLocalDatasource.getDatabaseStats();

    return SyncStats(
      totalProducts: productStats['total_products'] ?? 0,
      totalCategories: categoryStats['total_categories'] ?? 0,
      totalVariants: productStats['total_variants'] ?? 0,
      databaseSizeMB: (productStats['database_size_mb'] ?? 0.0) +
          (categoryStats['database_size_mb'] ?? 0.0),
    );
  }

  Future<void> _onCancelSync(
    _CancelSync event,
    Emitter<DataSyncState> emit,
  ) async {
    log('⏹️ Cancelling sync...');
    _isCancelled = true;
    _progressTimer?.cancel();
    emit(const DataSyncState.initial());
  }
}
