package com.social.media.domain.shared.events;

import lombok.Getter;

import java.time.Instant;
import java.util.Objects;
import java.util.UUID;

/**
 * Base class for all domain events.
 * 
 * Domain events represent something meaningful that happened in the domain.
 * They are immutable and carry the minimum necessary data.
 * 
 * @author Social Media Manager Team
 * @since 2.0.0
 */
@Getter
public abstract class DomainEvent {
    
    private final UUID eventId;
    private final Instant occurredAt;
    private final Long aggregateId;
    private final String aggregateType;
    private final Long aggregateVersion;
    
    protected DomainEvent(Long aggregateId, String aggregateType, Long aggregateVersion) {
        this.eventId = UUID.randomUUID();
        this.occurredAt = Instant.now();
        this.aggregateId = Objects.requireNonNull(aggregateId, "Aggregate ID cannot be null");
        this.aggregateType = Objects.requireNonNull(aggregateType, "Aggregate type cannot be null");
        this.aggregateVersion = Objects.requireNonNull(aggregateVersion, "Aggregate version cannot be null");
    }
    
    /**
     * Get event type name (class simple name)
     */
    public String getEventType() {
        return this.getClass().getSimpleName();
    }
    
    /**
     * Check if this event occurred before another event
     */
    public boolean occurredBefore(DomainEvent other) {
        return this.occurredAt.isBefore(other.occurredAt);
    }
    
    /**
     * Check if this event occurred after another event
     */
    public boolean occurredAfter(DomainEvent other) {
        return this.occurredAt.isAfter(other.occurredAt);
    }
    
    @Override
    public boolean equals(Object obj) {
        if (this == obj) return true;
        if (obj == null || getClass() != obj.getClass()) return false;
        DomainEvent that = (DomainEvent) obj;
        return Objects.equals(eventId, that.eventId);
    }
    
    @Override
    public int hashCode() {
        return Objects.hash(eventId);
    }
    
    @Override
    public String toString() {
        return String.format("%s{eventId=%s, aggregateId=%d, aggregateType='%s', aggregateVersion=%d, occurredAt=%s}",
            getEventType(), eventId, aggregateId, aggregateType, aggregateVersion, occurredAt);
    }
}
