import '../../../common/domain/metal_type.dart';

class AssetImage {
  const AssetImage({
    required this.localId,
    required this.localPath,
    required this.createdAt,
    this.remoteUrl,
    this.thumbnailUrl,
  });

  final String localId;
  final String localPath;
  final String? remoteUrl;
  final String? thumbnailUrl;
  final DateTime createdAt;

  AssetImage copyWith({
    String? localId,
    String? localPath,
    String? remoteUrl,
    String? thumbnailUrl,
    DateTime? createdAt,
  }) {
    return AssetImage(
      localId: localId ?? this.localId,
      localPath: localPath ?? this.localPath,
      remoteUrl: remoteUrl ?? this.remoteUrl,
      thumbnailUrl: thumbnailUrl ?? this.thumbnailUrl,
      createdAt: createdAt ?? this.createdAt,
    );
  }

  Map<String, dynamic> toJson() {
    return {
      'localId': localId,
      'localPath': localPath,
      'remoteUrl': remoteUrl,
      'thumbnailUrl': thumbnailUrl,
      'createdAt': createdAt.toIso8601String(),
    };
  }

  factory AssetImage.fromJson(Map<String, dynamic> json) {
    return AssetImage(
      localId: json['localId'] as String? ?? '',
      localPath: json['localPath'] as String? ?? '',
      remoteUrl: json['remoteUrl'] as String?,
      thumbnailUrl: json['thumbnailUrl'] as String?,
      createdAt: DateTime.tryParse(json['createdAt'] as String? ?? '') ??
          DateTime.fromMillisecondsSinceEpoch(0),
    );
  }
}

enum AssetCategory {
  bar('金条'),
  necklace('项链'),
  ring('戒指'),
  bracelet('手镯'),
  bean('金豆'),
  earring('耳环'),
  silverware('银饰'),
  platinumPiece('铂金件');

  const AssetCategory(this.label);

  final String label;
}

enum HoldingStatus { active, sold, gifted }

class GoldAssetHolding {
  const GoldAssetHolding({
    required this.id,
    required this.name,
    required this.metal,
    required this.category,
    required this.purity,
    required this.purityLabel,
    required this.weightGram,
    required this.createdAt,
    required this.updatedAt,
    this.images = const [],
    this.costAmount,
    this.purchaseDate,
    this.channel,
    this.note,
    this.status = HoldingStatus.active,
  });

  final String id;
  final String name;
  final MetalType metal;
  final AssetCategory category;
  final double purity;
  final String purityLabel;
  final double weightGram;
  final List<AssetImage> images;
  final double? costAmount;
  final DateTime? purchaseDate;
  final String? channel;
  final String? note;
  final DateTime createdAt;
  final DateTime updatedAt;
  final HoldingStatus status;

  GoldAssetHolding copyWith({
    String? id,
    String? name,
    MetalType? metal,
    AssetCategory? category,
    double? purity,
    String? purityLabel,
    double? weightGram,
    List<AssetImage>? images,
    double? costAmount,
    DateTime? purchaseDate,
    String? channel,
    String? note,
    DateTime? createdAt,
    DateTime? updatedAt,
    HoldingStatus? status,
  }) {
    return GoldAssetHolding(
      id: id ?? this.id,
      name: name ?? this.name,
      metal: metal ?? this.metal,
      category: category ?? this.category,
      purity: purity ?? this.purity,
      purityLabel: purityLabel ?? this.purityLabel,
      weightGram: weightGram ?? this.weightGram,
      images: images ?? this.images,
      costAmount: costAmount ?? this.costAmount,
      purchaseDate: purchaseDate ?? this.purchaseDate,
      channel: channel ?? this.channel,
      note: note ?? this.note,
      createdAt: createdAt ?? this.createdAt,
      updatedAt: updatedAt ?? this.updatedAt,
      status: status ?? this.status,
    );
  }

  double materialValue(double spotPrice) => weightGram * purity * spotPrice;

  Map<String, dynamic> toJson() {
    return {
      'id': id,
      'name': name,
      'metalId': metal.id,
      'categoryId': category.name,
      'purity': purity,
      'purityLabel': purityLabel,
      'weightGram': weightGram,
      'images': images.map((item) => item.toJson()).toList(growable: false),
      'costAmount': costAmount,
      'purchaseDate': purchaseDate?.toIso8601String(),
      'channel': channel,
      'note': note,
      'createdAt': createdAt.toIso8601String(),
      'updatedAt': updatedAt.toIso8601String(),
      'status': status.name,
    };
  }

  factory GoldAssetHolding.fromJson(Map<String, dynamic> json) {
    final rawImages = json['images'];
    return GoldAssetHolding(
      id: json['id'] as String? ?? '',
      name: json['name'] as String? ?? '',
      metal: _metalFromId(json['metalId'] as String?),
      category: _categoryFromId(json['categoryId'] as String?),
      purity: (json['purity'] as num?)?.toDouble() ?? 1,
      purityLabel: json['purityLabel'] as String? ?? '',
      weightGram: (json['weightGram'] as num?)?.toDouble() ?? 0,
      images: rawImages is List
          ? [
              for (final raw in rawImages)
                if (raw is Map)
                  AssetImage.fromJson(Map<String, dynamic>.from(raw)),
            ]
          : const [],
      costAmount: (json['costAmount'] as num?)?.toDouble(),
      purchaseDate: DateTime.tryParse(json['purchaseDate'] as String? ?? ''),
      channel: json['channel'] as String?,
      note: json['note'] as String?,
      createdAt: DateTime.tryParse(json['createdAt'] as String? ?? '') ??
          DateTime.fromMillisecondsSinceEpoch(0),
      updatedAt: DateTime.tryParse(json['updatedAt'] as String? ?? '') ??
          DateTime.fromMillisecondsSinceEpoch(0),
      status: _statusFromName(json['status'] as String?),
    );
  }
}

class HoldingValuation {
  const HoldingValuation({
    required this.holding,
    required this.materialValue,
    required this.todayChange,
  });

  final GoldAssetHolding holding;
  final double materialValue;
  final double todayChange;
}

class MetalBreakdown {
  const MetalBreakdown({
    required this.metal,
    required this.value,
    required this.weightGram,
    required this.count,
  });

  final MetalType metal;
  final double value;
  final double weightGram;
  final int count;
}

class PortfolioSummary {
  const PortfolioSummary({
    required this.totalValue,
    required this.todayChangeAmount,
    required this.todayChangePercent,
    required this.totalCost,
    required this.totalWeightGram,
    required this.recycleReferenceValue,
    required this.breakdowns,
    required this.holdings,
  });

  final double totalValue;
  final double todayChangeAmount;
  final double todayChangePercent;
  final double totalCost;
  final double totalWeightGram;
  final double recycleReferenceValue;
  final List<MetalBreakdown> breakdowns;
  final List<HoldingValuation> holdings;
}

MetalType _metalFromId(String? id) {
  return switch (id) {
    'gold' => MetalType.gold,
    'platinum' => MetalType.platinum,
    'silver' => MetalType.silver,
    _ => MetalType.gold,
  };
}

AssetCategory _categoryFromId(String? id) {
  return AssetCategory.values.firstWhere(
    (item) => item.name == id,
    orElse: () => AssetCategory.bar,
  );
}

HoldingStatus _statusFromName(String? value) {
  return HoldingStatus.values.firstWhere(
    (item) => item.name == value,
    orElse: () => HoldingStatus.active,
  );
}
