enum SuggestionStatus { pending, reviewed, implemented }

class Suggestion {
  const Suggestion({
    required this.id,
    required this.text,
    required this.isAnonymous,
    required this.submittedAt,
    required this.status,
    this.userId,
    this.displayName,
  });

  final String id;
  final String text;
  final bool isAnonymous;
  final String? userId;
  final String? displayName;
  final DateTime submittedAt;
  final SuggestionStatus status;

  Suggestion copyWith({
    String? id,
    String? text,
    bool? isAnonymous,
    String? userId,
    String? displayName,
    DateTime? submittedAt,
    SuggestionStatus? status,
  }) {
    return Suggestion(
      id: id ?? this.id,
      text: text ?? this.text,
      isAnonymous: isAnonymous ?? this.isAnonymous,
      userId: userId ?? this.userId,
      displayName: displayName ?? this.displayName,
      submittedAt: submittedAt ?? this.submittedAt,
      status: status ?? this.status,
    );
  }

  factory Suggestion.fromJson(Map<String, dynamic> data) {
    return Suggestion(
      id: (data['id'] as String?) ?? '',
      text: (data['text'] as String?) ?? '',
      isAnonymous: _parseBool(data['is_anonymous']),
      userId: data['user_id'] as String?,
      displayName: data['display_name'] as String?,
      submittedAt: _parseDate(data['submitted_at']) ?? DateTime.now(),
      status: _parseStatus(data['status'] as String?),
    );
  }

  Map<String, Object?> toJson() {
    return <String, Object?>{
      'text': text,
      'is_anonymous': isAnonymous,
      'user_id': isAnonymous ? null : userId,
      'display_name': isAnonymous ? null : displayName,
      'status': status.name,
    };
  }

  static DateTime? _parseDate(Object? v) {
    if (v is String && v.isNotEmpty) return DateTime.tryParse(v);
    return null;
  }

  static bool _parseBool(Object? v) {
    if (v is bool) return v;
    if (v is int) return v != 0;
    if (v is String) return v == '1' || v.toLowerCase() == 'true';
    return false;
  }

  static SuggestionStatus _parseStatus(String? raw) {
    switch (raw) {
      case 'reviewed':
        return SuggestionStatus.reviewed;
      case 'implemented':
        return SuggestionStatus.implemented;
      default:
        return SuggestionStatus.pending;
    }
  }

  @override
  bool operator ==(Object other) {
    if (identical(this, other)) return true;
    return other is Suggestion &&
        other.id == id &&
        other.text == text &&
        other.isAnonymous == isAnonymous &&
        other.userId == userId &&
        other.displayName == displayName &&
        other.submittedAt == submittedAt &&
        other.status == status;
  }

  @override
  int get hashCode => Object.hash(
        id, text, isAnonymous, userId, displayName, submittedAt, status,
      );

  @override
  String toString() =>
      'Suggestion(id: $id, status: ${status.name}, anonymous: $isAnonymous)';
}
