package com.social.media.domain.shared;

import java.time.Instant;
import java.util.Objects;
import java.util.UUID;

/**
 * Base abstract class for all Domain Entities with UUID identifiers.
 * 
 * Provides common functionality for entities including:
 * - UUID-based identity
 * - Timestamp tracking
 * - Equality and hash code based on ID
 * - Soft delete support
 * 
 * @author Social Media Manager Team
 * @version 2.0
 * @since 2025-01-01
 */
public abstract class BaseEntity implements Entity<UUID> {
    
    protected UUID id;
    protected Instant createdAt;
    protected Instant updatedAt;
    protected boolean deleted = false;
    
    /**
     * Default constructor for frameworks.
     */
    protected BaseEntity() {
        // Required for JPA and serialization
    }
    
    /**
     * Constructor for new entities.
     */
    protected BaseEntity(UUID id) {
        this.id = id;
        this.createdAt = Instant.now();
        this.updatedAt = Instant.now();
    }
    
    @Override
    public UUID getId() {
        return id;
    }
    
    @Override
    public Instant getCreatedAt() {
        return createdAt;
    }
    
    @Override
    public Instant getUpdatedAt() {
        return updatedAt;
    }
    
    /**
     * Checks if this entity is marked as deleted.
     * 
     * @return true if the entity is soft deleted
     */
    public boolean isDeleted() {
        return deleted;
    }
    
    /**
     * Marks this entity as deleted (soft delete).
     */
    public void markAsDeleted() {
        this.deleted = true;
        this.updatedAt = Instant.now();
    }
    
    /**
     * Restores this entity from deleted state.
     */
    public void restore() {
        this.deleted = false;
        this.updatedAt = Instant.now();
    }
    
    /**
     * Updates the modification timestamp.
     * Should be called whenever the entity is modified.
     */
    protected void touch() {
        this.updatedAt = Instant.now();
    }
    
    /**
     * Updates the modification timestamp (public version).
     * Should be called whenever the entity is modified.
     */
    public void markAsModified() {
        this.updatedAt = Instant.now();
    }
    
    /**
     * Sets the entity as persisted with timestamps.
     * Should only be called by persistence layer.
     */
    public void markAsPersisted(Instant createdAt, Instant updatedAt) {
        if (this.createdAt == null) {
            this.createdAt = createdAt;
        }
        this.updatedAt = updatedAt;
    }
    
    @Override
    public boolean equals(Object obj) {
        if (this == obj) {
            return true;
        }
        if (obj == null || getClass() != obj.getClass()) {
            return false;
        }
        
        BaseEntity that = (BaseEntity) obj;
        
        // If both entities are new (no ID), they are not equal
        if (this.id == null && that.id == null) {
            return false;
        }
        
        return Objects.equals(this.id, that.id);
    }
    
    @Override
    public int hashCode() {
        return Objects.hash(id);
    }
    
    @Override
    public String toString() {
        return getClass().getSimpleName() + 
               "{id=" + id + 
               ", createdAt=" + createdAt + 
               ", updatedAt=" + updatedAt + 
               ", deleted=" + deleted + 
               '}';
    }
}
