import 'package:flutter_test/flutter_test.dart';

import 'package:feature_orders/feature_orders.dart';

void main() {
  const mapper = WooCommerceOrderMapper();

  // ── Sample WooCommerce order JSON ──────────────────────────────────────────

  Map<String, dynamic> sampleOrderJson({
    String id = '1001',
    String status = 'processing',
    String firstName = 'Jane',
    String lastName = 'Doe',
    String email = 'jane.doe@example.com',
    String phone = '555-0100',
    String customerNote = '',
    String paymentMethodTitle = 'Credit Card',
    List<Map<String, dynamic>>? lineItems,
    List<Map<String, dynamic>>? metaData,
  }) {
    return {
      'id': int.parse(id),
      'status': status,
      'date_created': '2026-04-01T10:00:00',
      'customer_note': customerNote,
      'payment_method_title': paymentMethodTitle,
      'billing': {
        'first_name': firstName,
        'last_name': lastName,
        'email': email,
        'phone': phone,
        'address_1': '123 Main St',
        'city': 'Asheville',
        'state': 'NC',
        'postcode': '28801',
        'country': 'US',
      },
      'shipping': {
        'first_name': firstName,
        'last_name': lastName,
        'address_1': '123 Main St',
        'city': 'Asheville',
        'state': 'NC',
        'postcode': '28801',
        'country': 'US',
      },
      'line_items':
          lineItems ??
          [
            {
              'name': 'Floral Bowl Cozy',
              'sku': 'BC-FLR-001',
              'quantity': 2,
              'price': '12.99',
              'product_id': 42,
              'variation_id': 0,
              'meta_data': [],
            },
          ],
      'meta_data': metaData ?? [],
    };
  }

  // ── fromJson ───────────────────────────────────────────────────────────────

  group('WooCommerceOrderMapper.fromJson', () {
    test('maps id from integer field', () {
      final order = mapper.fromJson(sampleOrderJson(id: '1001'));
      expect(order.id, '1001');
    });

    test('maps customer name from billing first_name + last_name', () {
      final order = mapper.fromJson(sampleOrderJson(firstName: 'Jane', lastName: 'Doe'));
      expect(order.customerName, 'Jane Doe');
    });

    test('maps customer email from billing email', () {
      final order = mapper.fromJson(sampleOrderJson(email: 'jane@example.com'));
      expect(order.customerEmail, 'jane@example.com');
    });

    test('maps customer phone from billing phone', () {
      final order = mapper.fromJson(sampleOrderJson(phone: '828-555-0101'));
      expect(order.customerPhone, '828-555-0101');
    });

    test('maps payment method title', () {
      final order = mapper.fromJson(sampleOrderJson(paymentMethodTitle: 'PayPal'));
      expect(order.paymentMethod, 'PayPal');
    });

    test('maps source to online', () {
      final order = mapper.fromJson(sampleOrderJson());
      expect(order.source, OrderSource.online);
    });

    test('maps order date from date_created', () {
      final order = mapper.fromJson(sampleOrderJson());
      expect(order.orderDate, DateTime(2026, 4, 1, 10, 0, 0));
    });

    test('maps customer_note to orderNotes when non-empty', () {
      final order = mapper.fromJson(sampleOrderJson(customerNote: 'Please gift wrap.'));
      expect(order.orderNotes, ['Please gift wrap.']);
    });

    test('orderNotes is empty when customer_note is empty', () {
      final order = mapper.fromJson(sampleOrderJson(customerNote: ''));
      expect(order.orderNotes, isEmpty);
    });

    test('maps shipping address from shipping fields', () {
      final order = mapper.fromJson(sampleOrderJson());
      expect(order.shippingAddress, contains('123 Main St'));
      expect(order.shippingAddress, contains('Asheville'));
      expect(order.shippingAddress, contains('NC'));
    });

    test('maps line item product name', () {
      final order = mapper.fromJson(sampleOrderJson());
      expect(order.items.first.productName, 'Floral Bowl Cozy');
    });

    test('maps line item sku', () {
      final order = mapper.fromJson(sampleOrderJson());
      expect(order.items.first.sku, 'BC-FLR-001');
    });

    test('maps line item quantity', () {
      final order = mapper.fromJson(sampleOrderJson());
      expect(order.items.first.quantity, 2);
    });

    test('maps line item unit price from string', () {
      final order = mapper.fromJson(sampleOrderJson());
      expect(order.items.first.unitPrice, closeTo(12.99, 0.001));
    });

    test('maps line item productId when non-zero', () {
      final order = mapper.fromJson(sampleOrderJson());
      expect(order.items.first.productId, '42');
    });

    test('line item variationId is null when variation_id is 0', () {
      final order = mapper.fromJson(sampleOrderJson());
      expect(order.items.first.variationId, isNull);
    });

    test('maps line item variationId when non-zero', () {
      final json = sampleOrderJson(
        lineItems: [
          {
            'name': 'Variant Product',
            'sku': 'VP-001',
            'quantity': 1,
            'price': '9.99',
            'product_id': 10,
            'variation_id': 5,
            'meta_data': [],
          },
        ],
      );
      final order = mapper.fromJson(json);
      expect(order.items.first.variationId, '5');
    });

    test('maps line item customizations from non-private meta_data', () {
      final json = sampleOrderJson(
        lineItems: [
          {
            'name': 'Custom Bowl',
            'sku': 'CB-001',
            'quantity': 1,
            'price': '15.00',
            'product_id': 0,
            'variation_id': 0,
            'meta_data': [
              {'key': 'color', 'value': 'blue'},
              {'key': '_private', 'value': 'hidden'},
            ],
          },
        ],
      );
      final order = mapper.fromJson(json);
      expect(order.items.first.customizations['color'], 'blue');
      expect(order.items.first.customizations.containsKey('_private'), false);
    });

    test('extracts non-private meta_data into customFields', () {
      final json = sampleOrderJson(
        metaData: [
          {'key': 'gift_message', 'value': 'Happy Birthday!'},
          {'key': '_wc_internal', 'value': 'skip'},
        ],
      );
      final order = mapper.fromJson(json);
      expect(order.customFields['gift_message'], 'Happy Birthday!');
      expect(order.customFields.containsKey('_wc_internal'), false);
    });

    test('handles missing line_items gracefully', () {
      final json = Map<String, dynamic>.from(sampleOrderJson());
      json['line_items'] = null;
      final order = mapper.fromJson(json);
      expect(order.items, isEmpty);
    });
  });

  // ── fromJsonList ───────────────────────────────────────────────────────────

  group('WooCommerceOrderMapper.fromJsonList', () {
    test('maps a list of order JSON maps', () {
      final jsonList = [
        sampleOrderJson(id: '1'),
        sampleOrderJson(id: '2'),
        sampleOrderJson(id: '3'),
      ];
      final orders = mapper.fromJsonList(jsonList);
      expect(orders.length, 3);
      expect(orders.map((o) => o.id).toList(), ['1', '2', '3']);
    });

    test('returns empty list for empty input', () {
      expect(mapper.fromJsonList([]), isEmpty);
    });
  });

  // ── toWooCommerceStatus ────────────────────────────────────────────────────

  group('WooCommerceOrderMapper.toWooCommerceStatus', () {
    test('pending maps to pending', () {
      expect(WooCommerceOrderMapper.toWooCommerceStatus(OrderStatus.pending), 'pending');
    });

    test('processing maps to processing', () {
      expect(WooCommerceOrderMapper.toWooCommerceStatus(OrderStatus.processing), 'processing');
    });

    test('shipped maps to completed', () {
      expect(WooCommerceOrderMapper.toWooCommerceStatus(OrderStatus.shipped), 'completed');
    });

    test('delivered maps to completed', () {
      expect(WooCommerceOrderMapper.toWooCommerceStatus(OrderStatus.delivered), 'completed');
    });

    test('cancelled maps to cancelled', () {
      expect(WooCommerceOrderMapper.toWooCommerceStatus(OrderStatus.cancelled), 'cancelled');
    });

    test('onHold maps to on-hold', () {
      expect(WooCommerceOrderMapper.toWooCommerceStatus(OrderStatus.onHold), 'on-hold');
    });

    test('refunded maps to refunded', () {
      expect(WooCommerceOrderMapper.toWooCommerceStatus(OrderStatus.refunded), 'refunded');
    });

    test('failed maps to failed', () {
      expect(WooCommerceOrderMapper.toWooCommerceStatus(OrderStatus.failed), 'failed');
    });
  });

  // ── _mapStatus (via fromJson) ──────────────────────────────────────────────

  group('WooCommerceOrderMapper status mapping (fromJson)', () {
    test('processing status maps to OrderStatus.processing', () {
      final order = mapper.fromJson(sampleOrderJson(status: 'processing'));
      expect(order.status, OrderStatus.processing);
    });

    test('completed status maps to OrderStatus.delivered', () {
      final order = mapper.fromJson(sampleOrderJson(status: 'completed'));
      expect(order.status, OrderStatus.delivered);
    });

    test('cancelled status maps to OrderStatus.cancelled', () {
      final order = mapper.fromJson(sampleOrderJson(status: 'cancelled'));
      expect(order.status, OrderStatus.cancelled);
    });

    test('on-hold status maps to OrderStatus.onHold', () {
      final order = mapper.fromJson(sampleOrderJson(status: 'on-hold'));
      expect(order.status, OrderStatus.onHold);
    });

    test('refunded status maps to OrderStatus.refunded', () {
      final order = mapper.fromJson(sampleOrderJson(status: 'refunded'));
      expect(order.status, OrderStatus.refunded);
    });

    test('failed status maps to OrderStatus.failed', () {
      final order = mapper.fromJson(sampleOrderJson(status: 'failed'));
      expect(order.status, OrderStatus.failed);
    });

    test('unknown status defaults to OrderStatus.pending', () {
      final order = mapper.fromJson(sampleOrderJson(status: 'trash'));
      expect(order.status, OrderStatus.pending);
    });
  });

  // ── toCreateJson ───────────────────────────────────────────────────────────

  group('WooCommerceOrderMapper.toCreateJson', () {
    final sampleOrder = Order(
      id: 'KC-9999',
      customerName: 'Jane Doe',
      customerEmail: 'jane@example.com',
      customerPhone: '555-0100',
      orderDate: DateTime(2026, 4, 1),
      status: OrderStatus.pending,
      items: const [
        OrderItem(
          productName: 'Bowl Cozy',
          sku: 'BC-001',
          quantity: 2,
          unitPrice: 12.99,
          productId: '42',
        ),
      ],
      shippingAddress: '123 Main St, Asheville, NC 28801',
      orderNotes: ['Please gift wrap.'],
      paymentMethod: 'Cash',
    );

    test('includes status as WooCommerce string', () {
      final json = mapper.toCreateJson(sampleOrder);
      expect(json['status'], 'pending');
    });

    test('includes billing email', () {
      final json = mapper.toCreateJson(sampleOrder);
      expect((json['billing'] as Map)['email'], 'jane@example.com');
    });

    test('includes billing phone', () {
      final json = mapper.toCreateJson(sampleOrder);
      expect((json['billing'] as Map)['phone'], '555-0100');
    });

    test('includes customer_note from first orderNote', () {
      final json = mapper.toCreateJson(sampleOrder);
      expect(json['customer_note'], 'Please gift wrap.');
    });

    test('customer_note is empty when orderNotes is empty', () {
      final order = sampleOrder.copyWith(orderNotes: []);
      final json = mapper.toCreateJson(order);
      expect(json['customer_note'], '');
    });

    test('includes line items', () {
      final json = mapper.toCreateJson(sampleOrder);
      final lineItems = json['line_items'] as List;
      expect(lineItems.length, 1);
      expect(lineItems.first['name'], 'Bowl Cozy');
      expect(lineItems.first['quantity'], 2);
    });

    test('includes product_id in line item when set', () {
      final json = mapper.toCreateJson(sampleOrder);
      final lineItems = json['line_items'] as List;
      expect(lineItems.first['product_id'], 42);
    });
  });

  // ── OrderStatus new values ─────────────────────────────────────────────────

  group('OrderStatus new values', () {
    test('onHold is a valid OrderStatus', () {
      expect(OrderStatus.values, contains(OrderStatus.onHold));
    });

    test('refunded is a valid OrderStatus', () {
      expect(OrderStatus.values, contains(OrderStatus.refunded));
    });

    test('failed is a valid OrderStatus', () {
      expect(OrderStatus.values, contains(OrderStatus.failed));
    });

    test('OrderStatus has 8 values total', () {
      expect(OrderStatus.values.length, 8);
    });
  });

  // ── OrderItem new fields ───────────────────────────────────────────────────

  group('OrderItem new fields', () {
    test('productId defaults to null', () {
      const item = OrderItem(productName: 'Test', sku: 'T-001', quantity: 1, unitPrice: 5.0);
      expect(item.productId, isNull);
    });

    test('variationId defaults to null', () {
      const item = OrderItem(productName: 'Test', sku: 'T-001', quantity: 1, unitPrice: 5.0);
      expect(item.variationId, isNull);
    });

    test('customizations defaults to empty map', () {
      const item = OrderItem(productName: 'Test', sku: 'T-001', quantity: 1, unitPrice: 5.0);
      expect(item.customizations, isEmpty);
    });

    test('copyWith replaces productId', () {
      const item = OrderItem(productName: 'Test', sku: 'T-001', quantity: 1, unitPrice: 5.0);
      final updated = item.copyWith(productId: '99');
      expect(updated.productId, '99');
    });

    test('copyWith replaces customizations', () {
      const item = OrderItem(productName: 'Test', sku: 'T-001', quantity: 1, unitPrice: 5.0);
      final updated = item.copyWith(customizations: {'color': 'red'});
      expect(updated.customizations['color'], 'red');
    });
  });

  // ── Order new fields ───────────────────────────────────────────────────────

  group('Order new fields', () {
    final baseOrder = Order(
      id: 'KC-0001',
      customerName: 'Test',
      customerEmail: 'test@example.com',
      orderDate: DateTime(2026, 1, 1),
      status: OrderStatus.pending,
      items: const [],
      shippingAddress: '',
    );

    test('paymentMethod defaults to null', () {
      expect(baseOrder.paymentMethod, isNull);
    });

    test('source defaults to online', () {
      expect(baseOrder.source, OrderSource.online);
    });

    test('customFields defaults to empty map', () {
      expect(baseOrder.customFields, isEmpty);
    });

    test('copyWith replaces paymentMethod', () {
      final updated = baseOrder.copyWith(paymentMethod: 'Cash');
      expect(updated.paymentMethod, 'Cash');
    });

    test('copyWith replaces source', () {
      final updated = baseOrder.copyWith(source: OrderSource.market);
      expect(updated.source, OrderSource.market);
    });

    test('copyWith replaces customFields', () {
      final updated = baseOrder.copyWith(customFields: {'gift': 'true'});
      expect(updated.customFields['gift'], 'true');
    });
  });

  // ── OrderSource ────────────────────────────────────────────────────────────

  group('OrderSource', () {
    test('has online, market, and manual values', () {
      expect(OrderSource.values, contains(OrderSource.online));
      expect(OrderSource.values, contains(OrderSource.market));
      expect(OrderSource.values, contains(OrderSource.manual));
    });

    test('has 3 values total', () {
      expect(OrderSource.values.length, 3);
    });
  });
}
