enum ProductType {
  simple,
  variable,
  grouped,
  external,
  digital, // specific logic might be needed, often just 'simple' + virtual/downloadable properties
  downloadable, // usually property of simple/variable
  virtual, // usually property of simple/variable
  subscription,
  variableSubscription, // 'variable-subscription'
  bundle,
  composite,
  bookable,
  unknown,
}

abstract class Product {
  final int id;
  final String name;
  final ProductType type;
  final String status; // publish, private, draft, pending, future
  final String? sku;
  final String? price;
  final String? regularPrice;
  final String? salePrice;
  final String stockStatus; // instock, outofstock, onbackorder
  final bool manageStock;
  final int? stockQuantity;
  final List<ProductImage> images;
  final String description;
  final String shortDescription;
  final List<dynamic> metaData;

  Product({
    required this.id,
    required this.name,
    required this.type,
    required this.status,
    this.sku,
    this.price,
    this.regularPrice,
    this.salePrice,
    required this.stockStatus,
    this.manageStock = false,
    this.stockQuantity,
    this.images = const [],
    this.description = '',
    this.shortDescription = '',
    this.metaData = const [],
  });

  factory Product.fromJson(Map<String, dynamic> json) {
    final typeStr = json['type'] as String? ?? 'simple';
    final type = _parseType(typeStr);

    switch (type) {
      case ProductType.variable:
        return VariableProduct.fromJson(json, type);
      case ProductType.grouped:
        return GroupedProduct.fromJson(json, type);
      case ProductType.external:
        return ExternalProduct.fromJson(json, type);
      // Add other specific classes as needed.
      // For now, map others to SimpleProduct or a specific generic fallback if they don't have unique fields we critically need right now.
      default:
        // 'simple', 'booking', 'subscription', etc. unless they get their own class
        return SimpleProduct.fromJson(json, type);
    }
  }

  static ProductType _parseType(String type) {
    switch (type) {
      case 'simple': return ProductType.simple;
      case 'variable': return ProductType.variable;
      case 'grouped': return ProductType.grouped;
      case 'external': return ProductType.external;
      case 'subscription': return ProductType.subscription;
      case 'variable-subscription': return ProductType.variableSubscription;
      case 'bundle': return ProductType.bundle;
      case 'composite': return ProductType.composite;
      case 'booking': return ProductType.bookable;
      default: return ProductType.unknown;
    }
  }

  Map<String, dynamic> toJson() {
     return {
      'id': id,
      'name': name,
      'type': _typeToString(type),
      'status': status,
      'sku': sku,
      'regular_price': regularPrice,
      'sale_price': salePrice,
      'stock_status': stockStatus,
      'manage_stock': manageStock,
      'stock_quantity': stockQuantity,
      'images': images.map((i) => i.toJson()).toList(),
      'description': description,
      'short_description': shortDescription,
      'meta_data': metaData,
    };
  }
  
  String _typeToString(ProductType t) {
      // simplified reverse mapping
       switch (t) {
          case ProductType.simple: return 'simple';
          case ProductType.variable: return 'variable';
          case ProductType.grouped: return 'grouped';
          case ProductType.external: return 'external';
          case ProductType.subscription: return 'subscription';
          case ProductType.variableSubscription: return 'variable-subscription';
          case ProductType.bundle: return 'bundle';
          case ProductType.composite: return 'composite';
          case ProductType.bookable: return 'booking';
          default: return 'simple';
      }
  }
}

class ProductImage {
  final int id;
  final String src;
  final String name;
  final String alt;

  ProductImage({
    required this.id,
    required this.src,
    required this.name,
    required this.alt,
  });

  factory ProductImage.fromJson(Map<String, dynamic> json) {
    return ProductImage(
      id: json['id'] ?? 0,
      src: json['src'] ?? '',
      name: json['name'] ?? '',
      alt: json['alt'] ?? '',
    );
  }

  Map<String, dynamic> toJson() => {
    'id': id,
    'src': src,
    'name': name,
    'alt': alt,
  };
}

class SimpleProduct extends Product {
  final bool virtual;
  final bool downloadable;

  SimpleProduct({
    required super.id,
    required super.name,
    required super.type,
    required super.status,
    super.sku,
    super.price,
    super.regularPrice,
    super.salePrice,
    required super.stockStatus,
    super.manageStock,
    super.stockQuantity,
    super.images,
    super.description,
    super.shortDescription,
    super.metaData,
    this.virtual = false,
    this.downloadable = false,
  });

  factory SimpleProduct.fromJson(Map<String, dynamic> json, ProductType type) {
    return SimpleProduct(
      id: json['id'],
      name: json['name'] ?? '',
      type: type,
      status: json['status'] ?? 'publish',
      sku: json['sku'],
      price: json['price']?.toString(), // API returns string or number? Usually string in WC
      regularPrice: json['regular_price']?.toString(),
      salePrice: json['sale_price']?.toString(),
      stockStatus: json['stock_status'] ?? 'instock',
      manageStock: json['manage_stock'] ?? false,
      stockQuantity: json['stock_quantity'],
      images: (json['images'] as List?)?.map((e) => ProductImage.fromJson(e)).toList() ?? [],
      description: json['description'] ?? '',
      shortDescription: json['short_description'] ?? '',
      metaData: List.from(json['meta_data'] ?? []),
      virtual: json['virtual'] ?? false,
      downloadable: json['downloadable'] ?? false,
    );
  }
  
  @override
  Map<String, dynamic> toJson() {
    final m = super.toJson();
    m['virtual'] = virtual;
    m['downloadable'] = downloadable;
    return m;
  }
}

class VariableProduct extends Product {
  final List<int> variations;

  VariableProduct({
    required super.id,
    required super.name,
    required super.type,
    required super.status,
    super.sku,
    super.price,
    super.regularPrice,
    super.salePrice,
    required super.stockStatus,
    super.manageStock,
    super.stockQuantity,
    super.images,
    super.description,
    super.shortDescription,
    super.metaData,
    this.variations = const [],
  });
  
  factory VariableProduct.fromJson(Map<String, dynamic> json, ProductType type) {
    return VariableProduct(
      id: json['id'],
      name: json['name'] ?? '',
      type: type,
      status: json['status'] ?? 'publish',
      sku: json['sku'],
      price: json['price']?.toString(),
      regularPrice: json['regular_price']?.toString(),
      salePrice: json['sale_price']?.toString(),
      stockStatus: json['stock_status'] ?? 'instock',
      manageStock: json['manage_stock'] ?? false,
      stockQuantity: json['stock_quantity'],
      images: (json['images'] as List?)?.map((e) => ProductImage.fromJson(e)).toList() ?? [],
      description: json['description'] ?? '',
      shortDescription: json['short_description'] ?? '',
      metaData: List.from(json['meta_data'] ?? []),
      variations: (json['variations'] as List?)?.cast<int>() ?? [],
    );
  }
   
  @override
  Map<String, dynamic> toJson() {
    final m = super.toJson();
    m['variations'] = variations;
    return m;
  }
}

class Variation {
  final int id;
  final String sku;
  final String? price;
  final String? regularPrice;
  final String? salePrice;
  final String stockStatus;
  final bool manageStock;
  final int? stockQuantity;
  final List<Map<String, dynamic>> attributes; // e.g. [{id: 0, name: 'Color', option: 'Blue'}]
  final ProductImage? image;

  Variation({
    required this.id,
    this.sku = '',
    this.price,
    this.regularPrice,
    this.salePrice,
    this.stockStatus = 'instock',
    this.manageStock = false,
    this.stockQuantity,
    this.attributes = const [],
    this.image,
  });

  factory Variation.fromJson(Map<String, dynamic> json) {
    return Variation(
      id: json['id'],
      sku: json['sku'] ?? '',
      price: json['price']?.toString(),
      regularPrice: json['regular_price']?.toString(),
      salePrice: json['sale_price']?.toString(),
      stockStatus: json['stock_status'] ?? 'instock',
      manageStock: json['manage_stock'] ?? false,
      stockQuantity: json['stock_quantity'],
      attributes: List<Map<String, dynamic>>.from(json['attributes'] ?? []),
      image: json['image'] != null ? ProductImage.fromJson(json['image']) : null,
    );
  }

  Map<String, dynamic> toJson() => {
    'id': id,
    'sku': sku,
    'regular_price': regularPrice,
    'sale_price': salePrice,
    'stock_status': stockStatus,
    'manage_stock': manageStock,
    'stock_quantity': stockQuantity,
    'attributes': attributes,
    'image': image?.toJson(),
  };
}

class GroupedProduct extends Product {
  final List<int> groupedProducts;

  GroupedProduct({
    required super.id,
    required super.name,
    required super.type,
    required super.status,
    super.sku,
    super.price,
    super.regularPrice,
    super.salePrice,
    required super.stockStatus,
    super.manageStock,
    super.stockQuantity,
    super.images,
    super.description,
    super.shortDescription,
    super.metaData,
    this.groupedProducts = const [],
  });

  factory GroupedProduct.fromJson(Map<String, dynamic> json, ProductType type) {
    return GroupedProduct(
      id: json['id'],
      name: json['name'] ?? '',
      type: type,
      status: json['status'] ?? 'publish',
      sku: json['sku'],
      price: json['price']?.toString(),
      regularPrice: json['regular_price']?.toString(),
      salePrice: json['sale_price']?.toString(),
      stockStatus: json['stock_status'] ?? 'instock',
      manageStock: json['manage_stock'] ?? false,
      stockQuantity: json['stock_quantity'],
      images: (json['images'] as List?)?.map((e) => ProductImage.fromJson(e)).toList() ?? [],
      description: json['description'] ?? '',
      shortDescription: json['short_description'] ?? '',
      metaData: List.from(json['meta_data'] ?? []),
      groupedProducts: (json['grouped_products'] as List?)?.cast<int>() ?? [],
    );
  }
  
  @override
  Map<String, dynamic> toJson() {
    final m = super.toJson();
    m['grouped_products'] = groupedProducts;
    return m;
  }
}

class ExternalProduct extends Product {
  final String externalUrl;
  final String buttonText;

  ExternalProduct({
    required super.id,
    required super.name,
    required super.type,
    required super.status,
    super.sku,
    super.price,
    super.regularPrice,
    super.salePrice,
    required super.stockStatus,
    super.manageStock,
    super.stockQuantity,
    super.images,
    super.description,
    super.shortDescription,
    super.metaData,
    this.externalUrl = '',
    this.buttonText = '',
  });

  factory ExternalProduct.fromJson(Map<String, dynamic> json, ProductType type) {
    return ExternalProduct(
      id: json['id'],
      name: json['name'] ?? '',
      type: type,
      status: json['status'] ?? 'publish',
      sku: json['sku'],
      price: json['price']?.toString(),
      regularPrice: json['regular_price']?.toString(),
      salePrice: json['sale_price']?.toString(),
      stockStatus: json['stock_status'] ?? 'instock',
      manageStock: json['manage_stock'] ?? false,
      stockQuantity: json['stock_quantity'],
      images: (json['images'] as List?)?.map((e) => ProductImage.fromJson(e)).toList() ?? [],
      description: json['description'] ?? '',
      shortDescription: json['short_description'] ?? '',
      metaData: List.from(json['meta_data'] ?? []),
      externalUrl: json['external_url'] ?? '',
      buttonText: json['button_text'] ?? '',
    );
  }

  @override
  Map<String, dynamic> toJson() {
    final m = super.toJson();
    m['external_url'] = externalUrl;
    m['button_text'] = buttonText;
    return m;
  }
}
