import 'dart:developer';
import 'package:dartz/dartz.dart';
import 'package:enaklo_pos/data/datasources/category/category_local_datasource.dart';
import 'package:enaklo_pos/data/datasources/category/category_remote_datasource.dart';
import 'package:enaklo_pos/data/models/response/category_response_model.dart';

class CategoryRepository {
  static CategoryRepository? _instance;

  final CategoryLocalDatasource _localDatasource;
  final CategoryRemoteDatasource _remoteDatasource;

  CategoryRepository._internal()
      : _localDatasource = CategoryLocalDatasource.instance,
        _remoteDatasource = CategoryRemoteDatasource();

  static CategoryRepository get instance {
    _instance ??= CategoryRepository._internal();
    return _instance!;
  }

  // ========================================
  // SYNC STRATEGY: REMOTE-FIRST WITH LOCAL FALLBACK
  // ========================================
  Future<Either<String, CategoryResponseModel>> getCategories({
    int page = 1,
    int limit = 10,
    bool isActive = true,
    String? search,
    bool forceRemote = false,
  }) async {
    try {
      log('📱 Getting categories - page: $page, isActive: $isActive, search: $search, forceRemote: $forceRemote');

      // Clean expired cache
      _localDatasource.clearExpiredCache();

      // Check if we should try remote first
      if (forceRemote || !await _localDatasource.hasCategories()) {
        log('🌐 Attempting remote fetch first...');

        final remoteResult = await _getRemoteCategories(
          page: page,
          limit: limit,
          isActive: isActive,
        );

        return await remoteResult.fold(
          (failure) async {
            log('❌ Remote fetch failed: $failure');
            log('📱 Falling back to local data...');
            return _getLocalCategories(
              page: page,
              limit: limit,
              isActive: isActive,
              search: search,
            );
          },
          (response) async {
            log('✅ Remote fetch successful, syncing to local...');

            // Sync remote data to local
            if (response.data.categories.isNotEmpty) {
              await _syncToLocal(response.data.categories,
                  clearFirst: page == 1);
            }

            return Right(response);
          },
        );
      } else {
        log('📱 Using local data (cache available)...');
        return _getLocalCategories(
          page: page,
          limit: limit,
          isActive: isActive,
          search: search,
        );
      }
    } catch (e) {
      log('❌ Error in getCategories: $e');
      return Left('Gagal memuat kategori: $e');
    }
  }

  // ========================================
  // PURE LOCAL OPERATIONS
  // ========================================
  Future<Either<String, CategoryResponseModel>> _getLocalCategories({
    int page = 1,
    int limit = 10,
    bool isActive = true,
    String? search,
  }) async {
    try {
      final cachedCategories = await _localDatasource.getCachedCategories(
        page: page,
        limit: limit,
        isActive: isActive,
        search: search,
      );

      final totalCount = await _localDatasource.getTotalCount(
        isActive: isActive,
        search: search,
      );

      final categoryData = CategoryData(
        categories: cachedCategories,
        totalCount: totalCount,
        page: page,
        limit: limit,
        totalPages: totalCount > 0 ? (totalCount / limit).ceil() : 0,
      );

      final response = CategoryResponseModel(
        success: true,
        data: categoryData,
      );

      log('✅ Returned ${cachedCategories.length} local categories (${totalCount} total)');
      return Right(response);
    } catch (e) {
      log('❌ Error getting local categories: $e');
      return Left('Gagal memuat kategori dari database lokal: $e');
    }
  }

  // ========================================
  // REMOTE FETCH
  // ========================================
  Future<Either<String, CategoryResponseModel>> _getRemoteCategories({
    int page = 1,
    int limit = 10,
    bool isActive = true,
  }) async {
    try {
      log('🌐 Fetching categories from remote...');
      return await _remoteDatasource.getCategories(
        page: page,
        limit: limit,
        isActive: isActive,
      );
    } catch (e) {
      log('❌ Remote fetch error: $e');
      return Left('Gagal mengambil data dari server: $e');
    }
  }

  // ========================================
  // SYNC TO LOCAL
  // ========================================
  Future<void> _syncToLocal(List<CategoryModel> categories,
      {bool clearFirst = false}) async {
    try {
      log('💾 Syncing ${categories.length} categories to local database...');
      await _localDatasource.saveCategoriesBatch(categories,
          clearFirst: clearFirst);
      log('✅ Categories synced to local successfully');
    } catch (e) {
      log('❌ Error syncing categories to local: $e');
      rethrow;
    }
  }

  // ========================================
  // MANUAL SYNC OPERATIONS
  // ========================================
  Future<Either<String, String>> syncAllCategories() async {
    try {
      log('🔄 Starting manual sync of all categories...');

      int page = 1;
      const limit = 50; // Higher limit for bulk sync
      bool hasMore = true;
      int totalSynced = 0;

      // Clear local data first for fresh sync
      await _localDatasource.clearAllCategories();

      while (hasMore) {
        log('📄 Syncing page $page...');

        final result = await _remoteDatasource.getCategories(
          page: page,
          limit: limit,
          isActive: true,
        );

        await result.fold(
          (failure) async {
            log('❌ Sync failed at page $page: $failure');
            throw Exception(failure);
          },
          (response) async {
            final categories = response.data.categories;

            if (categories.isNotEmpty) {
              await _localDatasource.saveCategoriesBatch(
                categories,
                clearFirst: false, // Don't clear on subsequent pages
              );
              totalSynced += categories.length;

              // Check if we have more pages
              hasMore = page < response.data.totalPages;
              page++;

              log('📦 Page $page synced: ${categories.length} categories');
            } else {
              hasMore = false;
            }
          },
        );
      }

      final message = 'Berhasil sinkronisasi $totalSynced kategori';
      log('✅ $message');
      return Right(message);
    } catch (e) {
      final error = 'Gagal sinkronisasi kategori: $e';
      log('❌ $error');
      return Left(error);
    }
  }

  // ========================================
  // UTILITY METHODS
  // ========================================
  Future<Either<String, CategoryResponseModel>> refreshCategories({
    bool isActive = true,
    String? search,
  }) async {
    log('🔄 Refreshing categories...');
    clearCache();

    return await getCategories(
      page: 1,
      limit: 10,
      isActive: isActive,
      search: search,
      forceRemote: true, // Force remote refresh
    );
  }

  Future<CategoryModel?> getCategoryById(String id) async {
    log('🔍 Getting category by ID: $id');
    return await _localDatasource.getCategoryById(id);
  }

  Future<List<CategoryModel>> getAllCategories() async {
    log('📋 Getting all categories for dropdown...');
    return await _localDatasource.getAllCategories();
  }

  Future<bool> hasLocalCategories() async {
    final hasCategories = await _localDatasource.hasCategories();
    log('📊 Has local categories: $hasCategories');
    return hasCategories;
  }

  Future<Map<String, dynamic>> getDatabaseStats() async {
    final stats = await _localDatasource.getDatabaseStats();
    log('📊 Category database stats: $stats');
    return stats;
  }

  void clearCache() {
    log('🧹 Clearing category cache');
    _localDatasource.clearCache();
  }

  Future<bool> isLocalDatabaseReady() async {
    try {
      final stats = await getDatabaseStats();
      final categoryCount = stats['total_categories'] ?? 0;
      final isReady = categoryCount > 0;
      log('🔍 Category database ready: $isReady ($categoryCount categories)');
      return isReady;
    } catch (e) {
      log('❌ Error checking category database readiness: $e');
      return false;
    }
  }

  Future<void> clearAllCategories() async {
    try {
      log('🗑️ Clearing all categories from repository...');
      await _localDatasource.clearAllCategories();
      clearCache();
      log('✅ All categories cleared successfully');
    } catch (e) {
      log('❌ Error clearing all categories: $e');
      rethrow;
    }
  }
}
