import 'package:flutter/foundation.dart';
import '../domain/inventory_adjustment_result.dart';
import '../domain/inventory_item.dart';
import '../domain/inventory_status.dart';
import 'adjust_inventory_quantity.dart';
import 'create_inventory_item.dart';
import 'get_inventory_items.dart';
import 'update_inventory_item.dart';

/// Controller that manages the inventory workspace state, including
/// filtering by status, free-text search, item selection, and write actions.
class InventoryController extends ChangeNotifier {
  final GetInventoryItems _getInventoryItems;
  final AdjustInventoryQuantity _adjustInventoryQuantity;
  final CreateInventoryItem _createInventoryItem;
  final UpdateInventoryItem _updateInventoryItem;

  InventoryController(
    this._getInventoryItems,
    this._adjustInventoryQuantity,
    this._createInventoryItem,
    this._updateInventoryItem,
  );

  bool isLoading = false;
  bool isUpdating = false;
  Object? error;

  /// The last write action result, or `null` if no write has been performed.
  InventoryAdjustmentResult? lastActionResult;

  /// All items returned by the repository (unfiltered).
  List<InventoryItem> _allItems = [];

  /// The currently visible items after applying [activeFilter] and [searchQuery].
  List<InventoryItem> items = [];

  /// The currently selected item, if any.
  InventoryItem? selectedItem;

  /// The active status filter label, or `null` for "all".
  ///
  /// Recognised values: `'inStock'`, `'lowStock'`, `'outOfStock'`, `'draft'`.
  String? activeFilter;

  /// The current free-text search query applied to name / SKU.
  String searchQuery = '';

  /// Loads all inventory items and applies any current filter / search.
  Future<void> load() async {
    isLoading = true;
    error = null;
    notifyListeners();

    try {
      _allItems = await _getInventoryItems();
      _applyFilters();
    } catch (e) {
      error = e;
    } finally {
      isLoading = false;
      notifyListeners();
    }
  }

  /// Sets the status filter and recomputes the visible list.
  void setFilter(String? filter) {
    activeFilter = filter;
    _applyFilters();
    notifyListeners();
  }

  /// Sets the search query and recomputes the visible list.
  void setSearchQuery(String query) {
    searchQuery = query;
    _applyFilters();
    notifyListeners();
  }

  /// Selects an item for detail view / highlight.
  void selectItem(InventoryItem item) {
    selectedItem = item;
    notifyListeners();
  }

  /// Attempts to select an item by SKU. Returns `true` if found.
  bool selectBySku(String sku) {
    final match = _allItems.where((i) => i.sku == sku).firstOrNull;
    if (match != null) {
      selectedItem = match;
      notifyListeners();
      return true;
    }
    return false;
  }

  // ── Write actions ──────────────────────────────────────────────────────────

  /// Adjusts the quantity of the item with [id] by [delta].
  ///
  /// A positive [delta] adds stock; a negative [delta] removes stock.
  /// Sets [lastActionResult] and refreshes the list on success.
  Future<void> adjustQuantity(String id, int delta, String reason) async {
    isUpdating = true;
    lastActionResult = null;
    notifyListeners();

    try {
      final result = await _adjustInventoryQuantity(id, delta, reason);
      lastActionResult = result;
      if (result.success) {
        await _refreshItem(result.updatedItem!);
      }
    } catch (e) {
      lastActionResult = InventoryAdjustmentResult.failure(e.toString());
    } finally {
      isUpdating = false;
      notifyListeners();
    }
  }

  /// Creates a new inventory item and adds it to the list.
  Future<void> createItem(InventoryItem item) async {
    isUpdating = true;
    lastActionResult = null;
    notifyListeners();

    try {
      final created = await _createInventoryItem(item);
      _allItems = [..._allItems, created];
      _applyFilters();
      lastActionResult = InventoryAdjustmentResult.success(created);
    } catch (e) {
      lastActionResult = InventoryAdjustmentResult.failure(e.toString());
    } finally {
      isUpdating = false;
      notifyListeners();
    }
  }

  /// Updates an existing inventory item and refreshes the list.
  Future<void> updateItem(InventoryItem item) async {
    isUpdating = true;
    lastActionResult = null;
    notifyListeners();

    try {
      final updated = await _updateInventoryItem(item);
      await _refreshItem(updated);
      lastActionResult = InventoryAdjustmentResult.success(updated);
    } catch (e) {
      lastActionResult = InventoryAdjustmentResult.failure(e.toString());
    } finally {
      isUpdating = false;
      notifyListeners();
    }
  }

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

  /// Replaces the item in [_allItems] and re-applies filters.
  /// Also refreshes [selectedItem] if it matches the updated item.
  Future<void> _refreshItem(InventoryItem updated) async {
    // Update selectedItem BEFORE _applyFilters so the contains() check passes.
    if (selectedItem?.id == updated.id) {
      selectedItem = updated;
    }
    _allItems = [
      for (final i in _allItems)
        if (i.id == updated.id) updated else i,
    ];
    _applyFilters();
  }

  void _applyFilters() {
    var result = _allItems;

    // Status filter
    final status = _parseStatus(activeFilter);
    if (status != null) {
      result = result.where((i) => i.status == status).toList();
    }

    // Free-text search on name and SKU
    if (searchQuery.isNotEmpty) {
      final q = searchQuery.toLowerCase();
      result = result.where((i) {
        return i.name.toLowerCase().contains(q) || i.sku.toLowerCase().contains(q);
      }).toList();
    }

    items = result;

    // Keep selection valid; clear if the selected item is no longer visible.
    if (selectedItem != null && !items.contains(selectedItem)) {
      selectedItem = null;
    }
  }

  static InventoryStatus? _parseStatus(String? filter) {
    if (filter == null) return null;
    switch (filter) {
      case 'inStock':
        return InventoryStatus.inStock;
      case 'lowStock':
        return InventoryStatus.lowStock;
      case 'outOfStock':
        return InventoryStatus.outOfStock;
      case 'draft':
        return InventoryStatus.draft;
      default:
        return null;
    }
  }
}
