import 'dart:convert';

import 'package:hive_ce/hive.dart';

import 'package:worker/core/constants/api_constants.dart';
import 'package:worker/core/constants/storage_constants.dart';
import 'package:worker/features/products/domain/entities/product.dart';

part 'product_model.g.dart';

/// Product Model
///
/// Hive CE model for caching product data locally.
/// Maps to the 'products' table in the database.
///
/// Type ID: 2
@HiveType(typeId: HiveTypeIds.productModel)
class ProductModel extends HiveObject {
  ProductModel({
    required this.productId,
    required this.name,
    this.description,
    required this.basePrice,
    this.images,
    required this.thumbnail,
    this.imageCaptions,
    this.customLink360,
    this.specifications,
    this.itemGroupName,
    this.brand,
    this.conversionOfSm,
    this.introAttributes,
    required this.isActive,
    required this.isFeatured,
    this.erpnextItemCode,
    required this.createdAt,
    this.updatedAt,
  });

  /// Product ID (Primary Key)
  @HiveField(0)
  final String productId;

  /// Product name
  @HiveField(1)
  final String name;

  /// Product description
  @HiveField(2)
  final String? description;

  /// Base price
  @HiveField(3)
  final double basePrice;

  /// Product images (JSON encoded list of URLs)
  @HiveField(4)
  final String? images;

  /// Thumbnail image URL
  @HiveField(5)
  final String thumbnail;

  /// Image captions (JSON encoded map of image_url -> caption)
  @HiveField(6)
  final String? imageCaptions;

  /// Custom 360-degree view link
  @HiveField(7)
  final String? customLink360;

  /// Product specifications (JSON encoded)
  /// Contains: size, material, color, finish, etc.
  @HiveField(8)
  final String? specifications;

  /// Item group name (from ERPNext)
  @HiveField(9)
  final String? itemGroupName;

  /// Product brand
  @HiveField(10)
  final String? brand;

  /// Conversion factor for Square Meter UOM (tiles per m²)
  /// Used to calculate: Số viên = Số lượng × conversionOfSm
  @HiveField(17)
  final double? conversionOfSm;

  /// Intro attributes (JSON encoded list)
  /// Quick reference attributes from API: Size, Colour, UOM
  /// Example: [{"code": "Size", "value": "120x120"}, {"code": "UOM", "value": "2 viên/hộp"}]
  @HiveField(18)
  final String? introAttributes;

  /// Whether product is active
  @HiveField(12)
  final bool isActive;

  /// Whether product is featured
  @HiveField(13)
  final bool isFeatured;

  /// ERPNext item code for integration
  @HiveField(14)
  final String? erpnextItemCode;

  /// Product creation timestamp
  @HiveField(15)
  final DateTime createdAt;

  /// Last update timestamp
  @HiveField(16)
  final DateTime? updatedAt;

  // =========================================================================
  // JSON SERIALIZATION
  // =========================================================================

  /// Create ProductModel from API JSON
  ///
  /// Handles the new Frappe ERPNext API structure with full image URLs.
  /// API response structure:
  /// - name: Item code (e.g., "CHG S01P")
  /// - item_name: Display name
  /// - item_group_name: Category
  /// - brand: Brand name
  /// - thumbnail: Full image URL
  /// - image_list: Array of {image_name, image_url, description}
  /// - price: Product price
  /// - conversion_of_sm: Conversion factor
  /// - intro_attributes: Array of {code, value}
  /// - attributes: Array of {attribute, attribute_name, attribute_value}
  factory ProductModel.fromJson(Map<String, dynamic> json) {
    final now = DateTime.now();

    // Parse image_list array
    final List<String> imagesList = [];
    final Map<String, String> imageCaptionsMap = {};

    if (json['image_list'] != null && json['image_list'] is List) {
      final imageListData = json['image_list'] as List;
      for (final imgData in imageListData) {
        if (imgData is Map<String, dynamic> && imgData['image_url'] != null) {
          final imageUrl = imgData['image_url'] as String;
          imagesList.add(imageUrl);

          // Store image caption (image_name: Face A, Face B, etc.)
          if (imgData['image_name'] != null) {
            imageCaptionsMap[imageUrl] = imgData['image_name'] as String;
          }
        }
      }
    }

    // Parse attributes array into specifications map
    final Map<String, dynamic> specificationsMap = {};
    if (json['attributes'] != null && json['attributes'] is List) {
      final attributesData = json['attributes'] as List;
      for (final attr in attributesData) {
        if (attr is Map<String, dynamic> &&
            attr['attribute_name'] != null &&
            attr['attribute_value'] != null) {
          specificationsMap[attr['attribute_name'] as String] =
              attr['attribute_value'] as String;
        }
      }
    }

    // Parse intro_attributes array
    final List<Map<String, String>> introAttributesList = [];
    if (json['intro_attributes'] != null && json['intro_attributes'] is List) {
      final introAttrsData = json['intro_attributes'] as List;
      for (final attr in introAttrsData) {
        if (attr is Map<String, dynamic> &&
            attr['code'] != null &&
            attr['value'] != null) {
          introAttributesList.add({
            'code': attr['code'] as String,
            'value': attr['value'] as String,
          });
        }
      }
    }

    return ProductModel(
      productId: json['name'] as String, // Item code
      name: json['item_name'] as String? ?? json['name'] as String,
      description: json['description'] as String?, // May be null in API
      basePrice: (json['price'] as num?)?.toDouble() ?? 0.0,
      images: imagesList.isNotEmpty ? jsonEncode(imagesList) : null,
      thumbnail: json['thumbnail'] as String? ?? '',
      imageCaptions: imageCaptionsMap.isNotEmpty
          ? jsonEncode(imageCaptionsMap)
          : null,
      customLink360: json['custom_link_360'] as String?,
      specifications: specificationsMap.isNotEmpty
          ? jsonEncode(specificationsMap)
          : null,
      itemGroupName: json['item_group_name'] as String?,
      brand: json['brand'] as String?,
      conversionOfSm: json['conversion_of_sm'] != null
          ? (json['conversion_of_sm'] as num).toDouble()
          : null,
      introAttributes: introAttributesList.isNotEmpty
          ? jsonEncode(introAttributesList)
          : null,
      isActive: true, // Assume active if returned by API
      isFeatured: false, // Not provided by API
      erpnextItemCode: json['item_code'] as String? ?? json['name'] as String,
      createdAt: now, // Not provided by this API endpoint
      updatedAt: now,
    );
  }


  /// Create ProductModel from Wishlist API JSON
  ///
  /// The wishlist API returns a simplified product structure:
  /// - name: Item code (e.g., "GIB20 G04")
  /// - item_code: Item code (duplicate of name)
  /// - item_name: Display name (e.g., "Gibellina GIB20 G04")
  /// - item_group_name: Category (e.g., "OUTDOOR [20mm]")
  /// - custom_link_360: 360 view link
  /// - thumbnail: Thumbnail image URL
  /// - price: Price (usually 0 from wishlist)
  /// - currency: Currency code
  /// - conversion_of_sm: Conversion factor
  factory ProductModel.fromWishlistApi(Map<String, dynamic> json) {
    final now = DateTime.now();

    // Handle thumbnail URL
    String thumbnailUrl = '';
    if (json['thumbnail'] != null && (json['thumbnail'] as String).isNotEmpty) {
      final thumbnailPath = json['thumbnail'] as String;
      if (thumbnailPath.startsWith('http')) {
        thumbnailUrl = thumbnailPath;
      } else if (thumbnailPath.startsWith('/')) {
        thumbnailUrl = '${ApiConstants.baseUrl}$thumbnailPath';
      } else {
        thumbnailUrl = '${ApiConstants.baseUrl}/$thumbnailPath';
      }
    }

    return ProductModel(
      productId: json['item_code'] as String? ?? json['name'] as String,
      name: json['item_name'] as String? ?? json['name'] as String,
      description: null, // Not provided by wishlist API
      basePrice: (json['price'] as num?)?.toDouble() ?? 0.0,
      images: null, // Not provided by wishlist API
      thumbnail: thumbnailUrl,
      imageCaptions: null,
      customLink360: json['custom_link_360'] as String?,
      specifications: null,
      itemGroupName: json['item_group_name'] as String?,
      brand: null, // Not provided by wishlist API
      conversionOfSm: json['conversion_of_sm'] != null
          ? (json['conversion_of_sm'] as num).toDouble()
          : null,
      introAttributes: null,
      isActive: true, // Assume active if in wishlist
      isFeatured: false,
      erpnextItemCode: json['item_code'] as String? ?? json['name'] as String,
      createdAt: now,
      updatedAt: null,
    );
  }

  /// Convert ProductModel to JSON
  Map<String, dynamic> toJson() {
    return {
      'product_id': productId,
      'name': name,
      'description': description,
      'base_price': basePrice,
      'images': images != null ? jsonDecode(images!) : null,
      'thumbnail': thumbnail,
      'image_captions': imageCaptions != null
          ? jsonDecode(imageCaptions!)
          : null,
      'custom_link_360': customLink360,
      'specifications': specifications != null
          ? jsonDecode(specifications!)
          : null,
      'item_group_name': itemGroupName,
      'brand': brand,
      'conversion_of_sm': conversionOfSm,
      'intro_attributes': introAttributes != null
          ? jsonDecode(introAttributes!)
          : null,
      'is_active': isActive,
      'is_featured': isFeatured,
      'erpnext_item_code': erpnextItemCode,
      'created_at': createdAt.toIso8601String(),
      'updated_at': updatedAt?.toIso8601String(),
    };
  }

  // =========================================================================
  // HELPER METHODS
  // =========================================================================

  /// Get images as List
  List<String>? get imagesList {
    if (images == null) return null;
    try {
      final decoded = jsonDecode(images!) as List;
      return decoded.map((e) => e.toString()).toList();
    } catch (e) {
      return null;
    }
  }

  /// Get first image or placeholder
  String get primaryImage {
    final imgs = imagesList;
    if (imgs != null && imgs.isNotEmpty) {
      return imgs.first;
    }
    return ''; // Return empty string, UI should handle placeholder
  }

  /// Get image captions as Map
  Map<String, String>? get imageCaptionsMap {
    if (imageCaptions == null) return null;
    try {
      final decoded = jsonDecode(imageCaptions!) as Map<String, dynamic>;
      return decoded.map((key, value) => MapEntry(key, value.toString()));
    } catch (e) {
      return null;
    }
  }

  /// Get specifications as Map
  Map<String, dynamic>? get specificationsMap {
    if (specifications == null) return null;
    try {
      return jsonDecode(specifications!) as Map<String, dynamic>;
    } catch (e) {
      return null;
    }
  }

  /// Get intro attributes as List
  List<Map<String, String>>? get introAttributesList {
    if (introAttributes == null) return null;
    try {
      final decoded = jsonDecode(introAttributes!) as List;
      return decoded.map((e) {
        final map = e as Map<String, dynamic>;
        return {
          'code': map['code'].toString(),
          'value': map['value'].toString(),
        };
      }).toList();
    } catch (e) {
      return null;
    }
  }

  /// Get specific intro attribute value by code
  String? getIntroAttribute(String code) {
    final attrs = introAttributesList;
    if (attrs == null) return null;

    try {
      final attr = attrs.firstWhere(
        (attr) => attr['code']?.toLowerCase() == code.toLowerCase(),
      );
      return attr['value'];
    } catch (e) {
      return null;
    }
  }

  /// Get formatted price with currency
  String get formattedPrice {
    return '${basePrice.toStringAsFixed(0)}đ';
  }

  /// Check if product has 360 view
  bool get has360View => customLink360 != null && customLink360!.isNotEmpty;

  // =========================================================================
  // COPY WITH
  // =========================================================================

  /// Create a copy with updated fields
  ProductModel copyWith({
    String? productId,
    String? name,
    String? description,
    double? basePrice,
    String? images,
    String? thumbnail,
    String? imageCaptions,
    String? customLink360,
    String? specifications,
    String? itemGroupName,
    String? brand,
    double? conversionOfSm,
    String? introAttributes,
    bool? isActive,
    bool? isFeatured,
    String? erpnextItemCode,
    DateTime? createdAt,
    DateTime? updatedAt,
  }) {
    return ProductModel(
      productId: productId ?? this.productId,
      name: name ?? this.name,
      description: description ?? this.description,
      basePrice: basePrice ?? this.basePrice,
      images: images ?? this.images,
      thumbnail: thumbnail ?? this.thumbnail,
      imageCaptions: imageCaptions ?? this.imageCaptions,
      customLink360: customLink360 ?? this.customLink360,
      specifications: specifications ?? this.specifications,
      itemGroupName: itemGroupName ?? this.itemGroupName,
      brand: brand ?? this.brand,
      conversionOfSm: conversionOfSm ?? this.conversionOfSm,
      introAttributes: introAttributes ?? this.introAttributes,
      isActive: isActive ?? this.isActive,
      isFeatured: isFeatured ?? this.isFeatured,
      erpnextItemCode: erpnextItemCode ?? this.erpnextItemCode,
      createdAt: createdAt ?? this.createdAt,
      updatedAt: updatedAt ?? this.updatedAt,
    );
  }

  @override
  String toString() {
    return 'ProductModel(productId: $productId, name: $name, price: $basePrice)';
  }

  @override
  bool operator ==(Object other) {
    if (identical(this, other)) return true;

    return other is ProductModel && other.productId == productId;
  }

  @override
  int get hashCode => productId.hashCode;

  // =========================================================================
  // ENTITY CONVERSION
  // =========================================================================

  /// Convert ProductModel to Product entity
  Product toEntity() {
    return Product(
      productId: productId,
      name: name,
      description: description,
      basePrice: basePrice,
      images: imagesList ?? [],
      thumbnail: thumbnail,
      imageCaptions: imageCaptionsMap ?? {},
      customLink360: customLink360,
      specifications: specificationsMap ?? {},
      itemGroupName: itemGroupName,
      brand: brand,
      conversionOfSm: conversionOfSm,
      introAttributes: introAttributesList,
      isActive: isActive,
      isFeatured: isFeatured,
      erpnextItemCode: erpnextItemCode,
      createdAt: createdAt,
      updatedAt: updatedAt ?? createdAt,
    );
  }
}
