import 'package:flutter/foundation.dart';

import '../domain/order.dart';
import '../domain/order_action_result.dart';
import '../domain/order_status.dart';
import 'add_order_note.dart';
import 'create_order.dart';
import 'get_orders.dart';
import 'update_order_status.dart';

/// Controller that manages the orders workspace state, including
/// filtering by order status, free-text search, order selection,
/// and write operations (status update, note addition, order creation).
class OrdersController extends ChangeNotifier {
  final GetOrders _getOrders;
  final UpdateOrderStatus? _updateOrderStatus;
  final AddOrderNote? _addOrderNote;
  final CreateOrder? _createOrder;

  OrdersController(
    this._getOrders, {
    UpdateOrderStatus? updateOrderStatus,
    AddOrderNote? addOrderNote,
    CreateOrder? createOrder,
  }) : _updateOrderStatus = updateOrderStatus,
       _addOrderNote = addOrderNote,
       _createOrder = createOrder;

  bool isLoading = false;

  /// Whether a write operation is in progress for the selected order.
  bool isUpdating = false;

  Object? error;

  /// The result of the last write action, or `null` if none has been performed
  /// or the result has been consumed.
  OrderActionResult? lastActionResult;

  /// All orders returned by the repository (unfiltered).
  List<Order> _allOrders = [];

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

  /// The currently selected order for detail view.
  Order? selectedOrder;

  /// The active status filter label, or `null` for "all".
  ///
  /// Recognised values: `'pending'`, `'processing'`, `'shipped'`,
  /// `'delivered'`, `'cancelled'`.
  String? activeFilter;

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

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

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

    try {
      _allOrders = await _getOrders();
      _applyFilters();
      // Auto-select the first order if nothing is selected.
      selectedOrder ??= orders.isNotEmpty ? orders.first : null;
    } 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 order for detail view.
  void selectOrder(Order order) {
    selectedOrder = order;
    notifyListeners();
  }

  /// Attempts to select an order by ID. Returns `true` if found.
  bool selectById(String id) {
    final match = _allOrders.where((o) => o.id == id).firstOrNull;
    if (match != null) {
      selectedOrder = match;
      notifyListeners();
      return true;
    }
    return false;
  }

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

  /// Updates the status of the order identified by [id].
  ///
  /// Sets [isUpdating] during the operation and stores the result in
  /// [lastActionResult]. Reloads the order list on success and refreshes
  /// [selectedOrder] if it was the updated order.
  Future<void> updateOrderStatus(String id, OrderStatus newStatus) async {
    if (_updateOrderStatus == null) return;
    isUpdating = true;
    lastActionResult = null;
    notifyListeners();

    try {
      final result = await _updateOrderStatus(id, newStatus);
      lastActionResult = result;
      if (result.success) {
        await _reloadAndRefresh(id);
      }
    } finally {
      isUpdating = false;
      notifyListeners();
    }
  }

  /// Appends a note to the order identified by [id].
  ///
  /// Sets [isUpdating] during the operation and stores the result in
  /// [lastActionResult]. Refreshes [selectedOrder] on success.
  Future<void> addOrderNote(String id, String note) async {
    if (_addOrderNote == null) return;
    isUpdating = true;
    lastActionResult = null;
    notifyListeners();

    try {
      final result = await _addOrderNote(id, note);
      lastActionResult = result;
      if (result.success) {
        await _reloadAndRefresh(id);
      }
    } finally {
      isUpdating = false;
      notifyListeners();
    }
  }

  /// Creates a new order and adds it to the list.
  ///
  /// Sets [isUpdating] during the operation and stores the result in
  /// [lastActionResult]. Reloads the order list on success.
  Future<void> createOrder(Order order) async {
    if (_createOrder == null) return;
    isUpdating = true;
    lastActionResult = null;
    notifyListeners();

    try {
      final result = await _createOrder(order);
      lastActionResult = result;
      if (result.success) {
        await _reloadAndRefresh(null);
      }
    } finally {
      isUpdating = false;
      notifyListeners();
    }
  }

  /// Consumes and returns [lastActionResult], clearing it to `null`.
  OrderActionResult? consumeActionResult() {
    final result = lastActionResult;
    lastActionResult = null;
    return result;
  }

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

  /// Reloads all orders from the repository, re-applies filters, and
  /// refreshes [selectedOrder] by [selectedId] if provided.
  Future<void> _reloadAndRefresh(String? selectedId) async {
    _allOrders = await _getOrders();
    _applyFilters();

    // Refresh the selected order from the updated list.
    final refreshId = selectedId ?? selectedOrder?.id;
    if (refreshId != null) {
      final refreshed = _allOrders.where((o) => o.id == refreshId).firstOrNull;
      if (refreshed != null) {
        selectedOrder = refreshed;
      }
    }
  }

  void _applyFilters() {
    var result = _allOrders;

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

    // Free-text search on customer name and order ID
    if (searchQuery.isNotEmpty) {
      final q = searchQuery.toLowerCase();
      result = result.where((o) {
        return o.customerName.toLowerCase().contains(q) || o.id.toLowerCase().contains(q);
      }).toList();
    }

    orders = result;

    // Keep selection valid; clear if the selected order is no longer visible.
    if (selectedOrder != null && !orders.any((o) => o.id == selectedOrder!.id)) {
      selectedOrder = null;
    }
  }

  static OrderStatus? _parseStatus(String? filter) {
    if (filter == null) return null;
    switch (filter) {
      case 'pending':
        return OrderStatus.pending;
      case 'processing':
        return OrderStatus.processing;
      case 'shipped':
        return OrderStatus.shipped;
      case 'delivered':
        return OrderStatus.delivered;
      case 'cancelled':
        return OrderStatus.cancelled;
      default:
        return null;
    }
  }
}
