/// 出荷ステータス定義。
enum ShipmentStatus {
  pending,
  picking,
  ready,
  shipped,
  delivered,
  cancelled,
}

extension ShipmentStatusX on ShipmentStatus {
  String get displayName {
    switch (this) {
      case ShipmentStatus.pending:
        return '未手配';
      case ShipmentStatus.picking:
        return 'ピッキング中';
      case ShipmentStatus.ready:
        return '出荷待ち';
      case ShipmentStatus.shipped:
        return '出荷済み';
      case ShipmentStatus.delivered:
        return '納品済み';
      case ShipmentStatus.cancelled:
        return 'キャンセル';
    }
  }

  static ShipmentStatus fromDbValue(String? value) {
    return ShipmentStatus.values.firstWhere(
      (status) => status.name == value,
      orElse: () => ShipmentStatus.pending,
    );
  }
}

class ShipmentItem {
  ShipmentItem({
    required this.id,
    required this.shipmentId,
    required this.description,
    required this.quantity,
    this.orderItemId,
  });

  final String id;
  final String shipmentId;
  final String? orderItemId;
  final String description;
  final int quantity;

  Map<String, dynamic> toMap() => {
        'id': id,
        'shipment_id': shipmentId,
        'order_item_id': orderItemId,
        'description': description,
        'quantity': quantity,
      };

  factory ShipmentItem.fromMap(Map<String, dynamic> map) => ShipmentItem(
        id: map['id'] as String,
        shipmentId: map['shipment_id'] as String,
        orderItemId: map['order_item_id'] as String?,
        description: map['description'] as String,
        quantity: map['quantity'] as int? ?? 0,
      );
}

class Shipment {
  Shipment({
    required this.id,
    required this.status,
    required this.createdAt,
    required this.updatedAt,
    this.orderId,
    this.orderNumberSnapshot,
    this.customerNameSnapshot,
    this.scheduledShipDate,
    this.actualShipDate,
    this.carrierName,
    this.trackingNumber,
    this.trackingUrl,
    this.labelPdfPath,
    this.notes,
    this.pickingCompletedAt,
    this.items = const [],
  });

  final String id;
  final String? orderId;
  final String? orderNumberSnapshot;
  final String? customerNameSnapshot;
  final DateTime? scheduledShipDate;
  final DateTime? actualShipDate;
  final ShipmentStatus status;
  final String? carrierName;
  final String? trackingNumber;
  final String? trackingUrl;
  final String? labelPdfPath;
  final String? notes;
  final DateTime? pickingCompletedAt;
  final DateTime createdAt;
  final DateTime updatedAt;
  final List<ShipmentItem> items;

  Shipment copyWith({
    String? id,
    String? orderId,
    String? orderNumberSnapshot,
    String? customerNameSnapshot,
    DateTime? scheduledShipDate,
    DateTime? actualShipDate,
    ShipmentStatus? status,
    String? carrierName,
    String? trackingNumber,
    String? trackingUrl,
    String? labelPdfPath,
    String? notes,
    DateTime? pickingCompletedAt,
    DateTime? createdAt,
    DateTime? updatedAt,
    List<ShipmentItem>? items,
  }) {
    return Shipment(
      id: id ?? this.id,
      orderId: orderId ?? this.orderId,
      orderNumberSnapshot: orderNumberSnapshot ?? this.orderNumberSnapshot,
      customerNameSnapshot: customerNameSnapshot ?? this.customerNameSnapshot,
      scheduledShipDate: scheduledShipDate ?? this.scheduledShipDate,
      actualShipDate: actualShipDate ?? this.actualShipDate,
      status: status ?? this.status,
      carrierName: carrierName ?? this.carrierName,
      trackingNumber: trackingNumber ?? this.trackingNumber,
      trackingUrl: trackingUrl ?? this.trackingUrl,
      labelPdfPath: labelPdfPath ?? this.labelPdfPath,
      notes: notes ?? this.notes,
      pickingCompletedAt: pickingCompletedAt ?? this.pickingCompletedAt,
      createdAt: createdAt ?? this.createdAt,
      updatedAt: updatedAt ?? this.updatedAt,
      items: items ?? this.items,
    );
  }

  Map<String, dynamic> toMap() => {
        'id': id,
        'order_id': orderId,
        'order_number_snapshot': orderNumberSnapshot,
        'customer_name_snapshot': customerNameSnapshot,
        'scheduled_ship_date': scheduledShipDate?.toIso8601String(),
        'actual_ship_date': actualShipDate?.toIso8601String(),
        'status': status.name,
        'carrier_name': carrierName,
        'tracking_number': trackingNumber,
        'tracking_url': trackingUrl,
        'label_pdf_path': labelPdfPath,
        'notes': notes,
        'picking_completed_at': pickingCompletedAt?.toIso8601String(),
        'created_at': createdAt.toIso8601String(),
        'updated_at': updatedAt.toIso8601String(),
      };

  factory Shipment.fromMap(Map<String, dynamic> map, {List<ShipmentItem> items = const []}) {
    DateTime? parseNullable(String? value) => value == null ? null : DateTime.parse(value);
    return Shipment(
      id: map['id'] as String,
      orderId: map['order_id'] as String?,
      orderNumberSnapshot: map['order_number_snapshot'] as String?,
      customerNameSnapshot: map['customer_name_snapshot'] as String?,
      scheduledShipDate: parseNullable(map['scheduled_ship_date'] as String?),
      actualShipDate: parseNullable(map['actual_ship_date'] as String?),
      status: ShipmentStatusX.fromDbValue(map['status'] as String?),
      carrierName: map['carrier_name'] as String?,
      trackingNumber: map['tracking_number'] as String?,
      trackingUrl: map['tracking_url'] as String?,
      labelPdfPath: map['label_pdf_path'] as String?,
      notes: map['notes'] as String?,
      pickingCompletedAt: parseNullable(map['picking_completed_at'] as String?),
      createdAt: DateTime.parse(map['created_at'] as String),
      updatedAt: DateTime.parse(map['updated_at'] as String),
      items: items,
    );
  }

  ShipmentStatus nextDefaultStatus() {
    switch (status) {
      case ShipmentStatus.pending:
        return ShipmentStatus.picking;
      case ShipmentStatus.picking:
        return ShipmentStatus.ready;
      case ShipmentStatus.ready:
        return ShipmentStatus.shipped;
      case ShipmentStatus.shipped:
        return ShipmentStatus.delivered;
      case ShipmentStatus.delivered:
      case ShipmentStatus.cancelled:
        return status;
    }
  }
}
