package com.social.media.domain.shared.entities;

import org.springframework.data.annotation.CreatedDate;
import org.springframework.data.annotation.LastModifiedDate;
import org.springframework.data.jpa.domain.support.AuditingEntityListener;

import jakarta.persistence.*;
import lombok.Getter;
import lombok.Setter;

import java.time.Instant;
import java.util.Objects;

/**
 * Base class for all entities in the domain.
 * 
 * Provides common auditing fields and basic entity behavior.
 * Uses database-generated IDs for performance and simplicity.
 * 
 * @author Social Media Manager Team
 * @since 2.0.0
 */
@MappedSuperclass
@EntityListeners(AuditingEntityListener.class)
@Getter
@Setter
public abstract class BaseEntity {
    
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "id")
    private Long id;
    
    @CreatedDate
    @Column(name = "created_at", nullable = false, updatable = false)
    private Instant createdAt;
    
    @LastModifiedDate
    @Column(name = "updated_at", nullable = false)
    private Instant updatedAt;
    
    @Version
    @Column(name = "version", nullable = false)
    private Long version = 0L;
    
    @Column(name = "active", nullable = false)
    private Boolean active = true;
    
    /**
     * Check if entity is newly created (not persisted yet)
     */
    public boolean isNew() {
        return id == null;
    }
    
    /**
     * Check if entity is active
     */
    public boolean isActive() {
        return Boolean.TRUE.equals(active);
    }
    
    /**
     * Soft delete - mark as inactive
     */
    public void deactivate() {
        this.active = false;
    }
    
    /**
     * Reactivate entity
     */
    public void activate() {
        this.active = true;
    }
    
    /**
     * Called before entity is persisted
     */
    @PrePersist
    protected void prePersist() {
        if (createdAt == null) {
            createdAt = Instant.now();
        }
        if (updatedAt == null) {
            updatedAt = Instant.now();
        }
        if (active == null) {
            active = true;
        }
    }
    
    /**
     * Called before entity is updated
     */
    @PreUpdate
    protected void preUpdate() {
        updatedAt = Instant.now();
    }
    
    @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're equal only if they're the same instance
        if (this.isNew() && that.isNew()) {
            return this == that;
        }
        
        // If one is new and the other isn't, they're not equal
        if (this.isNew() || that.isNew()) {
            return false;
        }
        
        // Both have IDs, compare them
        return Objects.equals(id, that.id);
    }
    
    @Override
    public int hashCode() {
        // Use class hash code for new entities, ID hash code for persisted entities
        return isNew() ? getClass().hashCode() : Objects.hash(id);
    }
    
    @Override
    public String toString() {
        return String.format("%s{id=%s, version=%d, active=%s}", 
            getClass().getSimpleName(), id, version, active);
    }
}
