import '../../domain/entities/establishment.dart';

/// Modèle de données pour les établissements (Data Transfer Object).
class EstablishmentModel {
  EstablishmentModel({
    required this.id,
    required this.name,
    required this.type,
    required this.address,
    required this.city,
    required this.postalCode,
    this.description,
    this.phoneNumber,
    this.email,
    this.website,
    this.imageUrl,
    this.rating,
    this.priceRange,
    this.capacity,
    this.amenities = const [],
    this.openingHours,
    this.latitude,
    this.longitude,
  });

  /// Factory pour créer un [EstablishmentModel] à partir d'un JSON.
  factory EstablishmentModel.fromJson(Map<String, dynamic> json) {
    return EstablishmentModel(
      id: _parseId(json, 'id', ''),
      name: _parseString(json, 'name', ''),
      type: _parseType(json['type'] as String?),
      address: _parseString(json, 'address', ''),
      city: _parseString(json, 'city', ''),
      postalCode: _parseString(json, 'postalCode', ''),
      description: json['description'] as String?,
      phoneNumber: json['phoneNumber'] as String?,
      email: json['email'] as String?,
      website: json['website'] as String?,
      imageUrl: json['imageUrl'] as String?,
      rating: json['rating'] != null ? (json['rating'] as num).toDouble() : null,
      priceRange: _parsePriceRange(json['priceRange'] as String?),
      capacity: json['capacity'] as int?,
      amenities: json['amenities'] != null
          ? List<String>.from(json['amenities'] as List)
          : [],
      openingHours: json['openingHours'] as String?,
      latitude: json['latitude'] != null ? (json['latitude'] as num).toDouble() : null,
      longitude: json['longitude'] != null ? (json['longitude'] as num).toDouble() : null,
    );
  }

  final String id;
  final String name;
  final EstablishmentType type;
  final String address;
  final String city;
  final String postalCode;
  final String? description;
  final String? phoneNumber;
  final String? email;
  final String? website;
  final String? imageUrl;
  final double? rating;
  final PriceRange? priceRange;
  final int? capacity;
  final List<String> amenities;
  final String? openingHours;
  final double? latitude;
  final double? longitude;

  /// Convertit ce modèle en JSON pour l'envoi vers l'API.
  Map<String, dynamic> toJson() {
    return {
      'id': id,
      'name': name,
      'type': _typeToString(type),
      'address': address,
      'city': city,
      'postalCode': postalCode,
      if (description != null) 'description': description,
      if (phoneNumber != null) 'phoneNumber': phoneNumber,
      if (email != null) 'email': email,
      if (website != null) 'website': website,
      if (imageUrl != null) 'imageUrl': imageUrl,
      if (rating != null) 'rating': rating,
      if (priceRange != null) 'priceRange': _priceRangeToString(priceRange!),
      if (capacity != null) 'capacity': capacity,
      if (amenities.isNotEmpty) 'amenities': amenities,
      if (openingHours != null) 'openingHours': openingHours,
      if (latitude != null) 'latitude': latitude,
      if (longitude != null) 'longitude': longitude,
    };
  }

  /// Convertit ce modèle vers une entité de domaine [Establishment].
  Establishment toEntity() {
    return Establishment(
      id: id,
      name: name,
      type: type,
      address: address,
      city: city,
      postalCode: postalCode,
      description: description,
      phoneNumber: phoneNumber,
      email: email,
      website: website,
      imageUrl: imageUrl,
      rating: rating,
      priceRange: priceRange,
      capacity: capacity,
      amenities: amenities,
      openingHours: openingHours,
      latitude: latitude,
      longitude: longitude,
    );
  }

  // Méthodes de parsing
  static String _parseString(Map<String, dynamic> json, String key, String defaultValue) {
    return json[key] as String? ?? defaultValue;
  }

  static String _parseId(Map<String, dynamic> json, String key, String defaultValue) {
    final value = json[key];
    if (value == null) return defaultValue;
    return value.toString();
  }

  static EstablishmentType _parseType(String? type) {
    if (type == null) return EstablishmentType.other;

    switch (type.toLowerCase()) {
      case 'bar':
        return EstablishmentType.bar;
      case 'restaurant':
        return EstablishmentType.restaurant;
      case 'club':
        return EstablishmentType.club;
      case 'cafe':
      case 'café':
        return EstablishmentType.cafe;
      case 'lounge':
        return EstablishmentType.lounge;
      case 'pub':
        return EstablishmentType.pub;
      case 'brewery':
      case 'brasserie':
        return EstablishmentType.brewery;
      case 'winery':
      case 'cave':
        return EstablishmentType.winery;
      default:
        return EstablishmentType.other;
    }
  }

  static PriceRange? _parsePriceRange(String? priceRange) {
    if (priceRange == null) return null;

    switch (priceRange.toLowerCase()) {
      case 'cheap':
      case 'économique':
      case '€':
        return PriceRange.cheap;
      case 'moderate':
      case 'modéré':
      case '€€':
        return PriceRange.moderate;
      case 'expensive':
      case 'cher':
      case '€€€':
        return PriceRange.expensive;
      case 'luxury':
      case 'luxe':
      case '€€€€':
        return PriceRange.luxury;
      default:
        return null;
    }
  }

  static String _typeToString(EstablishmentType type) {
    return type.toString().split('.').last;
  }

  static String _priceRangeToString(PriceRange priceRange) {
    return priceRange.toString().split('.').last;
  }
}
