/// Data Model: Review
///
/// JSON serializable model for review data from API.
library;

import 'package:worker/features/reviews/domain/entities/review.dart';

/// Review data model
///
/// Handles JSON serialization/deserialization for review data from the API.
///
/// API Response format (assumed based on common Frappe patterns):
/// ```json
/// {
///   "name": "ITEM-{item_id}-{user_email}",
///   "item_id": "GIB20 G04",
///   "rating": 0.5,
///   "comment": "Good product",
///   "owner": "user@example.com",
///   "creation": "2024-11-17 10:30:00",
///   "modified": "2024-11-17 10:30:00"
/// }
/// ```
class ReviewModel {
  const ReviewModel({
    required this.name,
    required this.itemId,
    required this.rating,
    required this.comment,
    this.owner,
    this.ownerFullName,
    this.creation,
    this.modified,
  });

  /// Unique review identifier (format: ITEM-{item_id}-{user_email})
  final String name;

  /// Product item code
  final String itemId;

  /// Rating (0-1 scale from API)
  final double rating;

  /// Review comment text
  final String comment;

  /// Email of the review owner
  final String? owner;

  /// Full name of the review owner (if available)
  final String? ownerFullName;

  /// ISO 8601 timestamp when review was created
  final String? creation;

  /// ISO 8601 timestamp when review was last modified
  final String? modified;

  /// Create model from JSON
  factory ReviewModel.fromJson(Map<String, dynamic> json) {
    // Handle nested user object if present
    String? ownerEmail;
    String? fullName;

    if (json.containsKey('user') && json['user'] is Map<String, dynamic>) {
      final user = json['user'] as Map<String, dynamic>;
      ownerEmail = user['name'] as String?;
      fullName = user['full_name'] as String?;
    } else {
      ownerEmail = json['owner'] as String?;
      fullName = json['owner_full_name'] as String? ?? json['full_name'] as String?;
    }

    return ReviewModel(
      name: json['name'] as String,
      itemId: json['item_id'] as String? ?? '',
      rating: (json['rating'] as num).toDouble(),
      comment: json['comment'] as String? ?? '',
      owner: ownerEmail,
      ownerFullName: fullName,
      creation: json['creation'] as String?,
      modified: json['modified'] as String?,
    );
  }

  /// Convert model to JSON
  Map<String, dynamic> toJson() {
    return {
      'name': name,
      'item_id': itemId,
      'rating': rating,
      'comment': comment,
      if (owner != null) 'owner': owner,
      if (ownerFullName != null) 'owner_full_name': ownerFullName,
      if (creation != null) 'creation': creation,
      if (modified != null) 'modified': modified,
    };
  }

  /// Convert to domain entity
  Review toEntity() {
    return Review(
      id: name,
      itemId: itemId,
      rating: rating,
      comment: comment,
      reviewerName: ownerFullName ?? _extractNameFromEmail(owner),
      reviewerEmail: owner,
      reviewDate: creation != null ? _parseDateTime(creation!) : null,
    );
  }

  /// Create model from domain entity
  factory ReviewModel.fromEntity(Review entity) {
    return ReviewModel(
      name: entity.id,
      itemId: entity.itemId,
      rating: entity.rating,
      comment: entity.comment,
      owner: entity.reviewerEmail,
      ownerFullName: entity.reviewerName,
      creation: entity.reviewDate?.toIso8601String(),
    );
  }

  /// Extract name from email (fallback if full name not available)
  ///
  /// Example: "john.doe@example.com" -> "John Doe"
  String? _extractNameFromEmail(String? email) {
    if (email == null) return null;

    final username = email.split('@').first;
    final parts = username.split('.');

    return parts
        .map((part) => part.isEmpty
            ? ''
            : part[0].toUpperCase() + part.substring(1).toLowerCase())
        .join(' ');
  }

  /// Parse datetime string from API
  ///
  /// Handles common formats:
  /// - ISO 8601: "2024-11-17T10:30:00"
  /// - Frappe format: "2024-11-17 10:30:00"
  DateTime? _parseDateTime(String dateString) {
    try {
      // Try ISO 8601 first
      return DateTime.tryParse(dateString);
    } catch (e) {
      try {
        // Try replacing space with T for ISO 8601 compatibility
        final normalized = dateString.replaceFirst(' ', 'T');
        return DateTime.tryParse(normalized);
      } catch (e) {
        return null;
      }
    }
  }

  /// Copy with method
  ReviewModel copyWith({
    String? name,
    String? itemId,
    double? rating,
    String? comment,
    String? owner,
    String? ownerFullName,
    String? creation,
    String? modified,
  }) {
    return ReviewModel(
      name: name ?? this.name,
      itemId: itemId ?? this.itemId,
      rating: rating ?? this.rating,
      comment: comment ?? this.comment,
      owner: owner ?? this.owner,
      ownerFullName: ownerFullName ?? this.ownerFullName,
      creation: creation ?? this.creation,
      modified: modified ?? this.modified,
    );
  }

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

    return other is ReviewModel &&
        other.name == name &&
        other.itemId == itemId &&
        other.rating == rating &&
        other.comment == comment &&
        other.owner == owner &&
        other.ownerFullName == ownerFullName &&
        other.creation == creation &&
        other.modified == modified;
  }

  @override
  int get hashCode {
    return Object.hash(
      name,
      itemId,
      rating,
      comment,
      owner,
      ownerFullName,
      creation,
      modified,
    );
  }

  @override
  String toString() {
    return 'ReviewModel(name: $name, itemId: $itemId, rating: $rating, '
        'comment: ${comment.substring(0, comment.length > 30 ? 30 : comment.length)}..., '
        'owner: $owner, creation: $creation)';
  }
}
