import 'package:flutter_test/flutter_test.dart';

import 'package:feature_orders/feature_orders.dart';
import 'package:feature_orders/src/application/orders_controller.dart';

void main() {
  late FakeOrdersRepository repository;
  late OrdersController controller;

  setUp(() {
    repository = FakeOrdersRepository();
    controller = OrdersController(
      GetOrders(repository),
      updateOrderStatus: UpdateOrderStatus(repository),
      addOrderNote: AddOrderNote(repository),
      createOrder: CreateOrder(repository),
    );
  });

  tearDown(() {
    controller.dispose();
  });

  // ── Read-side tests (preserved from original) ──────────────────────────

  group('OrdersController — read', () {
    test('starts with empty state', () {
      expect(controller.isLoading, false);
      expect(controller.isUpdating, false);
      expect(controller.orders, isEmpty);
      expect(controller.selectedOrder, isNull);
      expect(controller.activeFilter, isNull);
      expect(controller.searchQuery, '');
      expect(controller.error, isNull);
      expect(controller.lastActionResult, isNull);
    });

    test('load populates orders and auto-selects first', () async {
      await controller.load();

      expect(controller.isLoading, false);
      expect(controller.orders.length, 6);
      expect(controller.selectedOrder, isNotNull);
      expect(controller.selectedOrder!.id, 'KC-1001');
      expect(controller.error, isNull);
    });

    test('selectOrder updates selectedOrder', () async {
      await controller.load();

      final third = controller.orders[2];
      controller.selectOrder(third);

      expect(controller.selectedOrder!.id, third.id);
    });

    test('setFilter filters by order status', () async {
      await controller.load();

      controller.setFilter('pending');
      expect(controller.orders.length, 2);
      expect(controller.orders.every((o) => o.status == OrderStatus.pending), true);
    });

    test('setFilter with null shows all orders', () async {
      await controller.load();

      controller.setFilter('cancelled');
      expect(controller.orders.length, 1);

      controller.setFilter(null);
      expect(controller.orders.length, 6);
    });

    test('setSearchQuery filters by customer name', () async {
      await controller.load();

      controller.setSearchQuery('sarah');
      expect(controller.orders.length, 1);
      expect(controller.orders.first.customerName, 'Sarah Mitchell');
    });

    test('setSearchQuery filters by order ID', () async {
      await controller.load();

      controller.setSearchQuery('KC-1003');
      expect(controller.orders.length, 1);
      expect(controller.orders.first.id, 'KC-1003');
    });

    test('filter and search combine', () async {
      await controller.load();

      controller.setFilter('pending');
      controller.setSearchQuery('david');
      expect(controller.orders.length, 1);
      expect(controller.orders.first.customerName, 'David Park');
    });

    test('selectById selects matching order', () async {
      await controller.load();

      final found = controller.selectById('KC-1004');
      expect(found, true);
      expect(controller.selectedOrder!.id, 'KC-1004');
    });

    test('selectById returns false for unknown ID', () async {
      await controller.load();

      final found = controller.selectById('UNKNOWN');
      expect(found, false);
    });

    test('selection is cleared when filtered out', () async {
      await controller.load();

      // Select a delivered order.
      controller.selectById('KC-1001');
      expect(controller.selectedOrder, isNotNull);

      // Filter to pending — the selected order should be cleared.
      controller.setFilter('pending');
      expect(controller.selectedOrder, isNull);
    });
  });

  // ── Write-side tests ───────────────────────────────────────────────────

  group('OrdersController — updateOrderStatus', () {
    test('updates status and sets success result', () async {
      await controller.load();
      controller.selectById('KC-1004');

      await controller.updateOrderStatus('KC-1004', OrderStatus.processing);

      expect(controller.isUpdating, false);
      expect(controller.lastActionResult, isNotNull);
      expect(controller.lastActionResult!.success, true);
      expect(controller.lastActionResult!.updatedOrder!.status, OrderStatus.processing);
    });

    test('refreshes selectedOrder after status update', () async {
      await controller.load();
      controller.selectById('KC-1004');

      await controller.updateOrderStatus('KC-1004', OrderStatus.processing);

      expect(controller.selectedOrder!.status, OrderStatus.processing);
    });

    test('reloads order list after status update', () async {
      await controller.load();

      // Initially 2 pending orders.
      controller.setFilter('pending');
      expect(controller.orders.length, 2);
      controller.setFilter(null);

      await controller.updateOrderStatus('KC-1004', OrderStatus.processing);

      // Now only 1 pending order.
      controller.setFilter('pending');
      expect(controller.orders.length, 1);
    });

    test('sets failure result for unknown order ID', () async {
      await controller.load();

      await controller.updateOrderStatus('UNKNOWN', OrderStatus.processing);

      expect(controller.lastActionResult!.success, false);
      expect(controller.lastActionResult!.errorMessage, isNotNull);
    });

    test('isUpdating is false after completion', () async {
      await controller.load();

      await controller.updateOrderStatus('KC-1004', OrderStatus.processing);

      expect(controller.isUpdating, false);
    });

    test('no-op when updateOrderStatus use case is not provided', () async {
      final readOnlyController = OrdersController(GetOrders(repository));
      await readOnlyController.load();

      await readOnlyController.updateOrderStatus('KC-1004', OrderStatus.processing);

      // No result set, no error.
      expect(readOnlyController.lastActionResult, isNull);
      readOnlyController.dispose();
    });
  });

  group('OrdersController — addOrderNote', () {
    test('adds note and sets success result', () async {
      await controller.load();
      controller.selectById('KC-1001');

      await controller.addOrderNote('KC-1001', 'Please gift wrap.');

      expect(controller.lastActionResult!.success, true);
      expect(controller.lastActionResult!.updatedOrder!.orderNotes, contains('Please gift wrap.'));
    });

    test('refreshes selectedOrder with new note', () async {
      await controller.load();
      controller.selectById('KC-1001');

      await controller.addOrderNote('KC-1001', 'Fragile item.');

      expect(controller.selectedOrder!.orderNotes, contains('Fragile item.'));
    });

    test('multiple notes accumulate', () async {
      await controller.load();

      await controller.addOrderNote('KC-1001', 'First note.');
      await controller.addOrderNote('KC-1001', 'Second note.');

      controller.selectById('KC-1001');
      expect(controller.selectedOrder!.orderNotes.length, 2);
    });

    test('sets failure result for empty note', () async {
      await controller.load();

      await controller.addOrderNote('KC-1001', '   ');

      expect(controller.lastActionResult!.success, false);
      expect(controller.lastActionResult!.errorMessage, isNotNull);
    });

    test('sets failure result for unknown order ID', () async {
      await controller.load();

      await controller.addOrderNote('UNKNOWN', 'Some note.');

      expect(controller.lastActionResult!.success, false);
    });

    test('no-op when addOrderNote use case is not provided', () async {
      final readOnlyController = OrdersController(GetOrders(repository));
      await readOnlyController.load();

      await readOnlyController.addOrderNote('KC-1001', 'Note.');

      expect(readOnlyController.lastActionResult, isNull);
      readOnlyController.dispose();
    });
  });

  group('OrdersController — createOrder', () {
    test('creates order and adds it to the list', () async {
      await controller.load();
      expect(controller.orders.length, 6);

      final newOrder = Order(
        id: 'KC-9999',
        customerName: 'New Customer',
        customerEmail: 'new@example.com',
        orderDate: DateTime(2026, 7, 1),
        status: OrderStatus.pending,
        items: const [
          OrderItem(productName: 'Test Product', sku: 'TP-001', quantity: 1, unitPrice: 15.00),
        ],
        shippingAddress: '1 New St, Test City, TC 00000',
      );

      await controller.createOrder(newOrder);

      expect(controller.lastActionResult!.success, true);
      expect(controller.orders.length, 7);
    });

    test('new order appears in list after creation', () async {
      await controller.load();

      final newOrder = Order(
        id: 'KC-8888',
        customerName: 'Another Customer',
        customerEmail: 'another@example.com',
        orderDate: DateTime(2026, 7, 2),
        status: OrderStatus.pending,
        items: const [
          OrderItem(productName: 'Widget', sku: 'WG-001', quantity: 2, unitPrice: 9.99),
        ],
        shippingAddress: '2 Another St, Test City, TC 00000',
      );

      await controller.createOrder(newOrder);

      final ids = controller.orders.map((o) => o.id).toList();
      expect(ids, contains('KC-8888'));
    });

    test('sets failure result for duplicate order ID', () async {
      await controller.load();

      final duplicate = Order(
        id: 'KC-1001',
        customerName: 'Duplicate',
        customerEmail: 'dup@example.com',
        orderDate: DateTime(2026, 7, 1),
        status: OrderStatus.pending,
        items: const [],
        shippingAddress: '',
      );

      await controller.createOrder(duplicate);

      expect(controller.lastActionResult!.success, false);
      expect(controller.lastActionResult!.errorMessage, isNotNull);
    });

    test('no-op when createOrder use case is not provided', () async {
      final readOnlyController = OrdersController(GetOrders(repository));
      await readOnlyController.load();

      final newOrder = Order(
        id: 'KC-7777',
        customerName: 'Test',
        customerEmail: 'test@example.com',
        orderDate: DateTime(2026, 7, 1),
        status: OrderStatus.pending,
        items: const [],
        shippingAddress: '',
      );

      await readOnlyController.createOrder(newOrder);

      expect(readOnlyController.lastActionResult, isNull);
      expect(readOnlyController.orders.length, 6);
      readOnlyController.dispose();
    });
  });

  group('OrdersController — consumeActionResult', () {
    test('consume clears lastActionResult', () async {
      await controller.load();
      await controller.updateOrderStatus('KC-1004', OrderStatus.processing);

      expect(controller.lastActionResult, isNotNull);
      final consumed = controller.consumeActionResult();
      expect(consumed, isNotNull);
      expect(controller.lastActionResult, isNull);
    });

    test('consume returns null when no result pending', () async {
      final result = controller.consumeActionResult();
      expect(result, isNull);
    });

    test('lastActionResult starts null', () {
      expect(controller.lastActionResult, isNull);
    });
  });

  group('OrdersController — filter/search persistence after writes', () {
    test('active filter is preserved after status update', () async {
      await controller.load();
      controller.setFilter('pending');
      expect(controller.orders.length, 2);

      await controller.updateOrderStatus('KC-1004', OrderStatus.processing);

      // Filter should still be active; now only 1 pending order.
      expect(controller.activeFilter, 'pending');
      expect(controller.orders.length, 1);
    });

    test('search query is preserved after note addition', () async {
      await controller.load();
      controller.setSearchQuery('sarah');
      expect(controller.orders.length, 1);

      await controller.addOrderNote('KC-1001', 'Test note.');

      expect(controller.searchQuery, 'sarah');
      expect(controller.orders.length, 1);
    });
  });
}
