import 'package:flutter_test/flutter_test.dart';

import 'package:feature_orders/feature_orders.dart';

void main() {
  late FakeOrdersRepository repository;

  setUp(() {
    repository = FakeOrdersRepository();
  });

  group('FakeOrdersRepository — read', () {
    test('getOrders returns six sample orders', () async {
      final orders = await repository.getOrders();
      expect(orders.length, 6);
    });

    test('getOrders returns orders with expected IDs', () async {
      final orders = await repository.getOrders();
      final ids = orders.map((o) => o.id).toList();
      expect(ids, contains('KC-1001'));
      expect(ids, contains('KC-1002'));
      expect(ids, contains('KC-1003'));
      expect(ids, contains('KC-1004'));
      expect(ids, contains('KC-1005'));
      expect(ids, contains('KC-1006'));
    });

    test('getOrders returns orders with various statuses', () async {
      final orders = await repository.getOrders();
      final statuses = orders.map((o) => o.status).toSet();
      expect(statuses, contains(OrderStatus.pending));
      expect(statuses, contains(OrderStatus.processing));
      expect(statuses, contains(OrderStatus.shipped));
      expect(statuses, contains(OrderStatus.delivered));
      expect(statuses, contains(OrderStatus.cancelled));
    });

    test('order totals are computed correctly', () async {
      final orders = await repository.getOrders();
      // KC-1001: 2 * 12.99 + 1 * 16.50 = 42.48
      final order1001 = orders.firstWhere((o) => o.id == 'KC-1001');
      expect(order1001.total, closeTo(42.48, 0.01));
    });

    test('order item count is computed correctly', () async {
      final orders = await repository.getOrders();
      // KC-1001: 2 + 1 = 3 items
      final order1001 = orders.firstWhere((o) => o.id == 'KC-1001');
      expect(order1001.itemCount, 3);
    });

    test('some orders have customerPhone set', () async {
      final orders = await repository.getOrders();
      final withPhone = orders.where((o) => o.customerPhone != null).toList();
      expect(withPhone, isNotEmpty);
    });
  });

  group('FakeOrdersRepository — updateOrderStatus', () {
    test('updates status of existing order', () async {
      final result = await repository.updateOrderStatus('KC-1004', OrderStatus.processing);

      expect(result.success, true);
      expect(result.updatedOrder!.id, 'KC-1004');
      expect(result.updatedOrder!.status, OrderStatus.processing);
    });

    test('persists status change across subsequent getOrders calls', () async {
      await repository.updateOrderStatus('KC-1004', OrderStatus.shipped);

      final orders = await repository.getOrders();
      final updated = orders.firstWhere((o) => o.id == 'KC-1004');
      expect(updated.status, OrderStatus.shipped);
    });

    test('returns failure for unknown order ID', () async {
      final result = await repository.updateOrderStatus('UNKNOWN', OrderStatus.processing);

      expect(result.success, false);
      expect(result.errorMessage, isNotNull);
    });

    test('can update to any valid status', () async {
      for (final status in OrderStatus.values) {
        final result = await repository.updateOrderStatus('KC-1001', status);
        expect(result.success, true);
        expect(result.updatedOrder!.status, status);
      }
    });
  });

  group('FakeOrdersRepository — addOrderNote', () {
    test('adds note to existing order', () async {
      final result = await repository.addOrderNote('KC-1001', 'Please gift wrap.');

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

    test('trims whitespace from note', () async {
      final result = await repository.addOrderNote('KC-1001', '  Trimmed note.  ');

      expect(result.updatedOrder!.orderNotes, contains('Trimmed note.'));
    });

    test('persists note across subsequent getOrders calls', () async {
      await repository.addOrderNote('KC-1001', 'Persistent note.');

      final orders = await repository.getOrders();
      final order = orders.firstWhere((o) => o.id == 'KC-1001');
      expect(order.orderNotes, contains('Persistent note.'));
    });

    test('multiple notes accumulate in order', () async {
      await repository.addOrderNote('KC-1001', 'First.');
      await repository.addOrderNote('KC-1001', 'Second.');

      final orders = await repository.getOrders();
      final order = orders.firstWhere((o) => o.id == 'KC-1001');
      expect(order.orderNotes.length, 2);
      expect(order.orderNotes[0], 'First.');
      expect(order.orderNotes[1], 'Second.');
    });

    test('returns failure for empty note', () async {
      final result = await repository.addOrderNote('KC-1001', '   ');

      expect(result.success, false);
      expect(result.errorMessage, isNotNull);
    });

    test('returns failure for unknown order ID', () async {
      final result = await repository.addOrderNote('UNKNOWN', 'Some note.');

      expect(result.success, false);
      expect(result.errorMessage, isNotNull);
    });
  });

  group('FakeOrdersRepository — createOrder', () {
    test('creates a new order and returns it', () async {
      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',
      );

      final result = await repository.createOrder(newOrder);

      expect(result.success, true);
      expect(result.updatedOrder!.id, 'KC-9999');
    });

    test('new order appears in subsequent getOrders calls', () async {
      final newOrder = Order(
        id: 'KC-8888',
        customerName: 'Another Customer',
        customerEmail: 'another@example.com',
        orderDate: DateTime(2026, 7, 2),
        status: OrderStatus.pending,
        items: const [],
        shippingAddress: '',
      );

      await repository.createOrder(newOrder);

      final orders = await repository.getOrders();
      expect(orders.length, 7);
      expect(orders.any((o) => o.id == 'KC-8888'), true);
    });

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

      final result = await repository.createOrder(duplicate);

      expect(result.success, false);
      expect(result.errorMessage, isNotNull);
    });

    test('duplicate rejection does not alter existing order', () async {
      final orders = await repository.getOrders();
      final original = orders.firstWhere((o) => o.id == 'KC-1001');

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

      await repository.createOrder(duplicate);

      final ordersAfter = await repository.getOrders();
      final unchanged = ordersAfter.firstWhere((o) => o.id == 'KC-1001');
      expect(unchanged.customerName, original.customerName);
      expect(unchanged.status, original.status);
    });
  });
}
