package com.social.media.domain.shared.valueobjects;

import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonValue;
import jakarta.persistence.MappedSuperclass;

import java.io.Serial;
import java.io.Serializable;
import java.util.Objects;
import java.util.UUID;

/**
 * Base class for all Entity IDs in the domain.
 * 
 * Implements type-safe ID pattern following DDD principles to prevent 
 * mixing different entity IDs and ensure strong typing.
 * 
 * Features:
 * - Uses UUID v4 for global uniqueness and better distribution in indexes
 * - Immutable value object with proper equals/hashCode implementation
 * - JSON serialization support for REST APIs
 * - Type safety to prevent incorrect ID assignments
 * - Optimized for database indexing performance
 * 
 * Pattern Usage:
 * <pre>
 * public final class CompanyId extends EntityId {
 *     public CompanyId() { super(); }
 *     public CompanyId(UUID value) { super(value); }
 *     public CompanyId(String value) { super(value); }
 * }
 * </pre>
 * 
 * @author Social Media Manager Team
 * @since 2.0.0
 */
@MappedSuperclass
public abstract class EntityId implements Serializable, Comparable<EntityId> {
    
    @Serial
    private static final long serialVersionUID = 1L;
    
    @JsonValue
    protected UUID value;
    
    /**
     * Constructor that generates a new random UUID
     */
    protected EntityId() {
        this.value = UUID.randomUUID();
    }
    
    /**
     * Constructor with existing UUID value
     * 
     * @param value The UUID value, must not be null
     * @throws IllegalArgumentException if value is null
     */
    protected EntityId(UUID value) {
        this.value = Objects.requireNonNull(value, "EntityId value cannot be null");
    }
    
    /**
     * Constructor with string representation of UUID
     * 
     * @param value The string UUID value, must not be null or invalid
     * @throws IllegalArgumentException if value is null or invalid UUID format
     */
    @JsonCreator
    protected EntityId(String value) {
        Objects.requireNonNull(value, "EntityId string value cannot be null");
        try {
            this.value = UUID.fromString(value.trim());
        } catch (IllegalArgumentException e) {
            throw new IllegalArgumentException("Invalid UUID format: " + value, e);
        }
    }
    
    /**
     * Generate a new random UUID for entity creation
     * 
     * @return A new random UUID
     */
    public static UUID newId() {
        return UUID.randomUUID();
    }
    
    /**
     * Get the UUID value
     * 
     * @return The internal UUID value
     */
    public UUID getValue() {
        return value;
    }
    
    /**
     * Get the string representation of the UUID
     * 
     * @return String representation of the UUID
     */
    public String getStringValue() {
        return value.toString();
    }
    
    /**
     * Check if this ID is empty (all zeros)
     * 
     * @return true if this is a nil/empty UUID
     */
    public boolean isEmpty() {
        return value.equals(new UUID(0, 0));
    }
    
    /**
     * Get the version of this UUID
     * 
     * @return The UUID version (typically 4 for random UUIDs)
     */
    public int getVersion() {
        return value.version();
    }
    
    @Override
    public boolean equals(Object obj) {
        if (this == obj) return true;
        if (obj == null || getClass() != obj.getClass()) return false;
        EntityId entityId = (EntityId) obj;
        return Objects.equals(value, entityId.value);
    }
    
    @Override
    public int hashCode() {
        return Objects.hash(value);
    }
    
    @Override
    public String toString() {
        return value.toString();
    }
    
    @Override
    public int compareTo(EntityId other) {
        if (other == null) return 1;
        return this.value.compareTo(other.value);
    }
}
