import '../domain/order.dart';
import '../domain/order_item.dart';
import '../domain/order_source.dart';
import '../domain/order_status.dart';

/// Maps raw WooCommerce REST API v3 order JSON into [Order] domain objects.
///
/// See https://woocommerce.github.io/woocommerce-rest-api-docs/#order-properties
class WooCommerceOrderMapper {
  const WooCommerceOrderMapper();

  /// Converts a single WooCommerce order JSON map to an [Order].
  Order fromJson(Map<String, dynamic> json) {
    final billing = json['billing'] as Map<String, dynamic>? ?? {};
    final shipping = json['shipping'] as Map<String, dynamic>? ?? {};

    final customerName = _buildName(billing);
    final customerEmail = (billing['email'] as String?) ?? '';
    final customerPhone = (billing['phone'] as String?);
    final shippingAddress = _buildAddress(shipping.isNotEmpty ? shipping : billing);

    final rawLineItems = json['line_items'];
    final items = rawLineItems is List
        ? rawLineItems.cast<Map<String, dynamic>>().map(_mapLineItem).toList()
        : <OrderItem>[];

    // Collect order notes from the customer_note field.
    final customerNote = (json['customer_note'] as String?) ?? '';
    final orderNotes = customerNote.isNotEmpty ? [customerNote] : <String>[];

    // Collect custom fields from meta_data.
    final customFields = _extractMetaData(json['meta_data']);

    return Order(
      id: json['id']?.toString() ?? '',
      customerName: customerName,
      customerEmail: customerEmail,
      customerPhone: customerPhone,
      orderDate: _parseDate(json['date_created']),
      status: _mapStatus(json['status'] as String?),
      items: items,
      shippingAddress: shippingAddress,
      orderNotes: orderNotes,
      paymentMethod: (json['payment_method_title'] as String?),
      source: OrderSource.online,
      customFields: customFields,
    );
  }

  /// Converts a list of WooCommerce order JSON maps to [Order]s.
  List<Order> fromJsonList(List<Map<String, dynamic>> jsonList) {
    return jsonList.map(fromJson).toList();
  }

  /// Converts an [OrderStatus] domain value to the corresponding
  /// WooCommerce REST API status string.
  ///
  /// WooCommerce order statuses: `pending`, `processing`, `on-hold`,
  /// `completed`, `cancelled`, `refunded`, `failed`, `trash`.
  static String toWooCommerceStatus(OrderStatus status) {
    switch (status) {
      case OrderStatus.pending:
        return 'pending';
      case OrderStatus.processing:
        return 'processing';
      case OrderStatus.shipped:
        // WooCommerce has no native "shipped" status; map to "completed"
        // as the closest equivalent for fulfilled orders.
        return 'completed';
      case OrderStatus.delivered:
        return 'completed';
      case OrderStatus.cancelled:
        return 'cancelled';
      case OrderStatus.onHold:
        return 'on-hold';
      case OrderStatus.refunded:
        return 'refunded';
      case OrderStatus.failed:
        return 'failed';
    }
  }

  /// Converts a WooCommerce order JSON map to the body needed for createOrder.
  Map<String, dynamic> toCreateJson(Order order) {
    return {
      'status': toWooCommerceStatus(order.status),
      'billing': {
        'first_name': order.customerName.split(' ').first,
        'last_name': order.customerName.split(' ').skip(1).join(' '),
        'email': order.customerEmail,
        'phone': order.customerPhone ?? '',
      },
      'customer_note': order.orderNotes.isNotEmpty ? order.orderNotes.first : '',
      'payment_method_title': order.paymentMethod ?? '',
      'line_items': order.items
          .map(
            (item) => {
              'name': item.productName,
              'quantity': item.quantity,
              'price': item.unitPrice.toStringAsFixed(2),
              if (item.productId != null) 'product_id': int.tryParse(item.productId!) ?? 0,
              if (item.variationId != null) 'variation_id': int.tryParse(item.variationId!) ?? 0,
            },
          )
          .toList(),
    };
  }

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

  /// Maps the WooCommerce order `status` string to our [OrderStatus] enum.
  static OrderStatus _mapStatus(String? status) {
    switch (status) {
      case 'pending':
        return OrderStatus.pending;
      case 'processing':
        return OrderStatus.processing;
      case 'completed':
        // WooCommerce "completed" maps to delivered (fully fulfilled).
        return OrderStatus.delivered;
      case 'cancelled':
        return OrderStatus.cancelled;
      case 'on-hold':
        return OrderStatus.onHold;
      case 'refunded':
        return OrderStatus.refunded;
      case 'failed':
        return OrderStatus.failed;
      default:
        return OrderStatus.pending;
    }
  }

  /// Maps a WooCommerce line item JSON to an [OrderItem].
  static OrderItem _mapLineItem(Map<String, dynamic> json) {
    final productId = json['product_id']?.toString();
    final variationId = json['variation_id']?.toString();

    // Extract customizations from meta_data (e.g. product attributes).
    final customizations = <String, String>{};
    final meta = json['meta_data'];
    if (meta is List) {
      for (final entry in meta.cast<Map<String, dynamic>>()) {
        final key = entry['key'] as String?;
        final value = entry['value'];
        if (key != null && value != null && !key.startsWith('_')) {
          customizations[key] = value.toString();
        }
      }
    }

    return OrderItem(
      productName: (json['name'] as String?) ?? '',
      sku: (json['sku'] as String?) ?? '',
      quantity: (json['quantity'] as int?) ?? 1,
      unitPrice: _parsePrice(json['price']),
      productId: (productId != null && productId != '0') ? productId : null,
      variationId: (variationId != null && variationId != '0') ? variationId : null,
      customizations: customizations,
    );
  }

  /// Builds a full name from a WooCommerce billing/shipping address map.
  static String _buildName(Map<String, dynamic> address) {
    final first = (address['first_name'] as String?) ?? '';
    final last = (address['last_name'] as String?) ?? '';
    return '$first $last'.trim();
  }

  /// Builds a single-line address string from a WooCommerce address map.
  static String _buildAddress(Map<String, dynamic> address) {
    final parts = <String>[
      (address['address_1'] as String?) ?? '',
      (address['address_2'] as String?) ?? '',
      (address['city'] as String?) ?? '',
      (address['state'] as String?) ?? '',
      (address['postcode'] as String?) ?? '',
      (address['country'] as String?) ?? '',
    ].where((s) => s.isNotEmpty).toList();
    return parts.join(', ');
  }

  /// Parses a price value that may arrive as a String or num.
  static double _parsePrice(dynamic value) {
    if (value == null) return 0.0;
    if (value is num) return value.toDouble();
    if (value is String) return double.tryParse(value) ?? 0.0;
    return 0.0;
  }

  /// Parses an ISO 8601 date string, falling back to [DateTime.now].
  static DateTime _parseDate(dynamic value) {
    if (value is String && value.isNotEmpty) {
      return DateTime.tryParse(value) ?? DateTime.now();
    }
    return DateTime.now();
  }

  /// Extracts non-private meta_data entries as a String→String map.
  static Map<String, String> _extractMetaData(dynamic metaData) {
    final result = <String, String>{};
    if (metaData is! List) return result;
    for (final entry in metaData.cast<Map<String, dynamic>>()) {
      final key = entry['key'] as String?;
      final value = entry['value'];
      // Skip WooCommerce internal meta keys (prefixed with '_').
      if (key != null && !key.startsWith('_') && value != null) {
        result[key] = value.toString();
      }
    }
    return result;
  }
}
