/// Local Data Source: Cart Storage
///
/// Handles local storage of cart items using Hive for offline access.
/// Supports offline-first functionality and cart persistence.
library;

import 'package:hive_ce/hive.dart';

import 'package:worker/core/constants/storage_constants.dart';
import 'package:worker/core/database/hive_service.dart';
import 'package:worker/core/errors/exceptions.dart';
import 'package:worker/features/cart/data/models/cart_item_model.dart';

/// Cart Local Data Source Interface
abstract class CartLocalDataSource {
  /// Save cart items to local storage
  ///
  /// [items] - List of cart items to save
  Future<void> saveCartItems(List<CartItemModel> items);

  /// Get cart items from local storage
  ///
  /// Returns list of cart items
  Future<List<CartItemModel>> getCartItems();

  /// Add item to local cart
  ///
  /// [item] - Cart item to add
  Future<void> addCartItem(CartItemModel item);

  /// Update item in local cart
  ///
  /// [item] - Cart item to update
  Future<void> updateCartItem(CartItemModel item);

  /// Remove items from local cart
  ///
  /// [itemIds] - Product IDs to remove
  Future<void> removeCartItems(List<String> itemIds);

  /// Clear all items from local cart
  Future<void> clearCart();

  /// Get cart item count
  ///
  /// Returns total number of items
  Future<int> getCartItemCount();

  /// Get cart total
  ///
  /// Returns total amount
  Future<double> getCartTotal();
}

/// Cart Local Data Source Implementation
class CartLocalDataSourceImpl implements CartLocalDataSource {
  CartLocalDataSourceImpl(this._hiveService);

  final HiveService _hiveService;

  /// Get cart box as Box<dynamic> (following best practices)
  Box<dynamic> get _cartBox => _hiveService.getBox<dynamic>(HiveBoxNames.cartBox);

  @override
  Future<void> saveCartItems(List<CartItemModel> items) async {
    try {
      // Clear existing items
      await _cartBox.clear();

      // Save new items with productId as key
      for (final item in items) {
        await _cartBox.put(item.productId, item);
      }
    } catch (e) {
      throw StorageException('Failed to save cart items: $e');
    }
  }

  @override
  Future<List<CartItemModel>> getCartItems() async {
    try {
      // Get all cart items from box using .whereType() for type safety
      final items = _cartBox.values
          .whereType<CartItemModel>()
          .toList();

      return items;
    } catch (e) {
      throw StorageException('Failed to get cart items: $e');
    }
  }

  @override
  Future<void> addCartItem(CartItemModel item) async {
    try {
      // Check if item already exists
      final existingItem = _cartBox.get(item.productId);

      if (existingItem != null && existingItem is CartItemModel) {
        // Update quantity if item exists
        final updatedItem = existingItem.copyWith(
          quantity: existingItem.quantity + item.quantity,
          subtotal: (existingItem.quantity + item.quantity) * existingItem.unitPrice,
        );
        await _cartBox.put(item.productId, updatedItem);
      } else {
        // Add new item
        await _cartBox.put(item.productId, item);
      }
    } catch (e) {
      throw StorageException('Failed to add cart item: $e');
    }
  }

  @override
  Future<void> updateCartItem(CartItemModel item) async {
    try {
      // Update or add item
      await _cartBox.put(item.productId, item);
    } catch (e) {
      throw StorageException('Failed to update cart item: $e');
    }
  }

  @override
  Future<void> removeCartItems(List<String> itemIds) async {
    try {
      // Remove items by productId keys
      for (final itemId in itemIds) {
        await _cartBox.delete(itemId);
      }
    } catch (e) {
      throw StorageException('Failed to remove cart items: $e');
    }
  }

  @override
  Future<void> clearCart() async {
    try {
      await _cartBox.clear();
    } catch (e) {
      throw StorageException('Failed to clear cart: $e');
    }
  }

  @override
  Future<int> getCartItemCount() async {
    try {
      final items = await getCartItems();

      // Sum up all quantities
      final totalQuantity = items.fold<double>(
        0.0,
        (sum, item) => sum + item.quantity,
      );

      return totalQuantity.toInt();
    } catch (e) {
      throw StorageException('Failed to get cart item count: $e');
    }
  }

  @override
  Future<double> getCartTotal() async {
    try {
      final items = await getCartItems();

      // Sum up all subtotals
      final total = items.fold<double>(
        0.0,
        (sum, item) => sum + item.subtotal,
      );

      return total;
    } catch (e) {
      throw StorageException('Failed to get cart total: $e');
    }
  }
}
