import 'package:feature_wordpress/feature_wordpress.dart';

import '../domain/inventory_adjustment_result.dart';
import '../domain/inventory_item.dart';
import '../domain/inventory_repository.dart';
import '../domain/inventory_status.dart';
import '../domain/inventory_sync_status.dart';

/// WooCommerce-backed implementation of [InventoryRepository].
///
/// Stock quantities are read from and written to WooCommerce product stock
/// fields via [WooCommerceApiClient]. All other inventory fields (name, SKU,
/// description, etc.) are managed locally and are not pushed to WooCommerce
/// by this repository — only `stock_quantity` and `manage_stock` are synced.
///
/// Items without a [InventoryItem.wooCommerceProductId] are stored in-memory
/// only and are not synced to WooCommerce.
class WooCommerceInventoryRepository implements InventoryRepository {
  final WooCommerceApiClient _apiClient;

  /// In-memory store for all inventory items (local source of truth).
  final List<InventoryItem> _items;

  WooCommerceInventoryRepository({
    required WooCommerceApiClient apiClient,
    List<InventoryItem> initialItems = const [],
  }) : _apiClient = apiClient,
       _items = List.of(initialItems);

  // ── Read operations ────────────────────────────────────────────────────────

  @override
  Future<List<InventoryItem>> getInventoryItems() async {
    return List.unmodifiable(_items);
  }

  @override
  Future<InventoryItem?> getItemBySku(String sku) async {
    try {
      return _items.firstWhere((i) => i.sku == sku);
    } catch (_) {
      return null;
    }
  }

  // ── Write operations ───────────────────────────────────────────────────────

  @override
  Future<InventoryAdjustmentResult> adjustQuantity(String id, int delta, String reason) async {
    final index = _items.indexWhere((i) => i.id == id);
    if (index == -1) {
      return const InventoryAdjustmentResult.failure('Item not found');
    }

    final item = _items[index];
    final newQty = item.quantityOnHand + delta;
    if (newQty < 0) {
      return const InventoryAdjustmentResult.failure('Quantity cannot go below zero');
    }

    // Push to WooCommerce if this item has a linked product.
    if (item.wooCommerceProductId != null) {
      try {
        await _apiClient.updateProductStock(item.wooCommerceProductId.toString(), newQty);
      } catch (e) {
        return InventoryAdjustmentResult.failure('WooCommerce stock update failed: $e');
      }
    }

    final updated = item.copyWith(
      quantityOnHand: newQty,
      status: _deriveStatus(newQty, item.reorderPoint),
      lastUpdated: DateTime.now(),
      lastSyncedAt: item.wooCommerceProductId != null ? DateTime.now() : item.lastSyncedAt,
      syncStatus: item.wooCommerceProductId != null
          ? InventorySyncStatus.synced
          : InventorySyncStatus.notSynced,
    );
    _items[index] = updated;
    return InventoryAdjustmentResult.success(updated);
  }

  @override
  Future<InventoryAdjustmentResult> setQuantity(String id, int quantity, String reason) async {
    if (quantity < 0) {
      return const InventoryAdjustmentResult.failure('Quantity cannot be negative');
    }

    final index = _items.indexWhere((i) => i.id == id);
    if (index == -1) {
      return const InventoryAdjustmentResult.failure('Item not found');
    }

    final item = _items[index];

    // Push to WooCommerce if this item has a linked product.
    if (item.wooCommerceProductId != null) {
      try {
        await _apiClient.updateProductStock(item.wooCommerceProductId.toString(), quantity);
      } catch (e) {
        return InventoryAdjustmentResult.failure('WooCommerce stock update failed: $e');
      }
    }

    final updated = item.copyWith(
      quantityOnHand: quantity,
      status: _deriveStatus(quantity, item.reorderPoint),
      lastUpdated: DateTime.now(),
      lastSyncedAt: item.wooCommerceProductId != null ? DateTime.now() : item.lastSyncedAt,
      syncStatus: item.wooCommerceProductId != null
          ? InventorySyncStatus.synced
          : InventorySyncStatus.notSynced,
    );
    _items[index] = updated;
    return InventoryAdjustmentResult.success(updated);
  }

  @override
  Future<InventoryItem> createItem(InventoryItem item) async {
    _items.add(item);
    return item;
  }

  @override
  Future<InventoryItem> updateItem(InventoryItem item) async {
    final index = _items.indexWhere((i) => i.id == item.id);
    if (index == -1) {
      throw StateError('Item with id ${item.id} not found');
    }
    final updated = item.copyWith(lastUpdated: DateTime.now());
    _items[index] = updated;
    return updated;
  }

  @override
  Future<InventoryAdjustmentResult> updateItemImage(String id, String imageUrl) async {
    final index = _items.indexWhere((i) => i.id == id);
    if (index == -1) {
      return const InventoryAdjustmentResult.failure('Item not found');
    }
    final updated = _items[index].copyWith(imageUrl: imageUrl, lastUpdated: DateTime.now());
    _items[index] = updated;
    return InventoryAdjustmentResult.success(updated);
  }

  @override
  Future<InventoryAdjustmentResult> syncWithRemote(
    String id,
    int remoteQuantity,
    String reason,
  ) async {
    if (remoteQuantity < 0) {
      return const InventoryAdjustmentResult.failure('Remote quantity cannot be negative');
    }

    final index = _items.indexWhere((i) => i.id == id);
    if (index == -1) {
      return const InventoryAdjustmentResult.failure('Item not found');
    }

    final item = _items[index];
    final updated = item.copyWith(
      quantityOnHand: remoteQuantity,
      status: _deriveStatus(remoteQuantity, item.reorderPoint),
      lastUpdated: DateTime.now(),
      lastSyncedAt: DateTime.now(),
      syncStatus: InventorySyncStatus.synced,
    );
    _items[index] = updated;
    return InventoryAdjustmentResult.success(updated);
  }

  // ── Private helpers ────────────────────────────────────────────────────────

  static InventoryStatus _deriveStatus(int quantity, int reorderPoint) {
    if (quantity == 0) return InventoryStatus.outOfStock;
    if (quantity <= reorderPoint) return InventoryStatus.lowStock;
    return InventoryStatus.inStock;
  }
}
