package com.social.media.domain.entity;

import jakarta.persistence.*;
import jakarta.validation.constraints.*;
import org.hibernate.annotations.JdbcTypeCode;
import org.hibernate.type.SqlTypes;

import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.Map;
import java.util.Objects;

@Entity
@Table(name = "campaigns", schema = "core_business",
       uniqueConstraints = {
           @UniqueConstraint(name = "campaigns_campaign_code_key", columnNames = {"campaign_code"})
       },
       indexes = {
           @Index(name = "idx_campaigns_company_id", columnList = "company_id"),
           @Index(name = "idx_campaigns_created_by", columnList = "created_by"),
           @Index(name = "idx_campaigns_status", columnList = "status"),
           @Index(name = "idx_campaigns_is_active", columnList = "is_active"),
           @Index(name = "idx_campaigns_start_date", columnList = "start_date"),
           @Index(name = "idx_campaigns_end_date", columnList = "end_date"),
           @Index(name = "idx_campaigns_deleted", columnList = "deleted")
       })
public class Campaign {
    
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    
    @Column(name = "campaign_code", nullable = false, unique = true, length = 20)
    private String campaignCode;
    
    @NotNull(message = "Company ID é obrigatório")
    @Column(name = "company_id", nullable = false)
    private Long companyId;
    
    @NotNull(message = "Created by é obrigatório")
    @Column(name = "created_by", nullable = false)
    private Long createdBy;
    
    @NotBlank(message = "Nome da campanha é obrigatório")
    @Size(max = 255, message = "Nome deve ter no máximo 255 caracteres")
    @Column(name = "name", nullable = false, length = 255)
    private String name;
    
    @Column(name = "description", columnDefinition = "TEXT")
    private String description;
    
    @NotNull(message = "Status é obrigatório")
    @Enumerated(EnumType.STRING)
    @Column(name = "status", nullable = false)
    private CampaignStatus status = CampaignStatus.DRAFT;
    
    @Column(name = "start_date")
    private LocalDateTime startDate;
    
    @Column(name = "end_date")
    private LocalDateTime endDate;
    
    @DecimalMin(value = "0.0", message = "Orçamento deve ser no mínimo 0.0")
    @Column(name = "budget", precision = 10, scale = 2)
    private BigDecimal budget;
    
    @JdbcTypeCode(SqlTypes.JSON)
    @Column(name = "target_audience_criteria", columnDefinition = "jsonb")
    private Map<String, Object> targetAudienceCriteria;
    
    @JdbcTypeCode(SqlTypes.JSON)
    @Column(name = "goals", columnDefinition = "jsonb")
    private Map<String, Object> goals;
    
    @JdbcTypeCode(SqlTypes.JSON)
    @Column(name = "metrics", columnDefinition = "jsonb")
    private Map<String, Object> metrics;
    
    @Column(name = "is_active", nullable = false)
    private Boolean isActive = true;
    
    @Column(name = "deleted", nullable = false)
    private Boolean deleted = false;
    
    @Column(name = "created_at", nullable = false)
    private LocalDateTime createdAt;
    
    @Column(name = "updated_at", nullable = false)
    private LocalDateTime updatedAt;
    
    // Enums
    public enum CampaignStatus {
        DRAFT, ACTIVE, PAUSED, COMPLETED, CANCELLED
    }
    
    // Constructors
    public Campaign() {}
    
    public Campaign(Long companyId, Long createdBy, String name) {
        this.companyId = companyId;
        this.createdBy = createdBy;
        this.name = name;
        this.createdAt = LocalDateTime.now();
        this.updatedAt = LocalDateTime.now();
    }
    
    public Campaign(Long companyId, Long createdBy, String name, String description) {
        this(companyId, createdBy, name);
        this.description = description;
    }
    
    // Lifecycle callbacks
    @PrePersist
    protected void onCreate() {
        LocalDateTime now = LocalDateTime.now();
        if (createdAt == null) {
            createdAt = now;
        }
        updatedAt = now;
        
        // Set default values if not provided
        if (status == null) {
            status = CampaignStatus.DRAFT;
        }
        if (isActive == null) {
            isActive = true;
        }
        if (deleted == null) {
            deleted = false;
        }
    }
    
    @PreUpdate
    protected void onUpdate() {
        updatedAt = LocalDateTime.now();
    }
    
    // Business methods
    public void activate() {
        this.status = CampaignStatus.ACTIVE;
        this.isActive = true;
        if (this.startDate == null) {
            this.startDate = LocalDateTime.now();
        }
    }
    
    public void pause() {
        this.status = CampaignStatus.PAUSED;
    }
    
    public void complete() {
        this.status = CampaignStatus.COMPLETED;
        this.isActive = false;
        if (this.endDate == null) {
            this.endDate = LocalDateTime.now();
        }
    }
    
    public void cancel() {
        this.status = CampaignStatus.CANCELLED;
        this.isActive = false;
        if (this.endDate == null) {
            this.endDate = LocalDateTime.now();
        }
    }
    
    public void softDelete() {
        this.deleted = true;
        this.isActive = false;
    }
    
    public boolean isRunning() {
        return status == CampaignStatus.ACTIVE && isActive && !deleted;
    }
    
    public boolean isScheduled() {
        return startDate != null && startDate.isAfter(LocalDateTime.now());
    }
    
    public boolean isExpired() {
        return endDate != null && endDate.isBefore(LocalDateTime.now());
    }
    
    // Getters and Setters
    public Long getId() {
        return id;
    }
    
    public void setId(Long id) {
        this.id = id;
    }
    
    public String getCampaignCode() {
        return campaignCode;
    }
    
    public void setCampaignCode(String campaignCode) {
        this.campaignCode = campaignCode;
    }
    
    public Long getCompanyId() {
        return companyId;
    }
    
    public void setCompanyId(Long companyId) {
        this.companyId = companyId;
    }
    
    public Long getCreatedBy() {
        return createdBy;
    }
    
    public void setCreatedBy(Long createdBy) {
        this.createdBy = createdBy;
    }
    
    public String getName() {
        return name;
    }
    
    public void setName(String name) {
        this.name = name;
    }
    
    public String getDescription() {
        return description;
    }
    
    public void setDescription(String description) {
        this.description = description;
    }
    
    public CampaignStatus getStatus() {
        return status;
    }
    
    public void setStatus(CampaignStatus status) {
        this.status = status;
    }
    
    public LocalDateTime getStartDate() {
        return startDate;
    }
    
    public void setStartDate(LocalDateTime startDate) {
        this.startDate = startDate;
    }
    
    public LocalDateTime getEndDate() {
        return endDate;
    }
    
    public void setEndDate(LocalDateTime endDate) {
        this.endDate = endDate;
    }
    
    public BigDecimal getBudget() {
        return budget;
    }
    
    public void setBudget(BigDecimal budget) {
        this.budget = budget;
    }
    
    public Map<String, Object> getTargetAudienceCriteria() {
        return targetAudienceCriteria;
    }
    
    public void setTargetAudienceCriteria(Map<String, Object> targetAudienceCriteria) {
        this.targetAudienceCriteria = targetAudienceCriteria;
    }
    
    public Map<String, Object> getGoals() {
        return goals;
    }
    
    public void setGoals(Map<String, Object> goals) {
        this.goals = goals;
    }
    
    public Map<String, Object> getMetrics() {
        return metrics;
    }
    
    public void setMetrics(Map<String, Object> metrics) {
        this.metrics = metrics;
    }
    
    public Boolean getIsActive() {
        return isActive;
    }
    
    public void setIsActive(Boolean isActive) {
        this.isActive = isActive;
    }
    
    public Boolean getDeleted() {
        return deleted;
    }
    
    public void setDeleted(Boolean deleted) {
        this.deleted = deleted;
    }
    
    public LocalDateTime getCreatedAt() {
        return createdAt;
    }
    
    public void setCreatedAt(LocalDateTime createdAt) {
        this.createdAt = createdAt;
    }
    
    public LocalDateTime getUpdatedAt() {
        return updatedAt;
    }
    
    public void setUpdatedAt(LocalDateTime updatedAt) {
        this.updatedAt = updatedAt;
    }
    
    // equals and hashCode
    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        Campaign campaign = (Campaign) o;
        return Objects.equals(id, campaign.id) && Objects.equals(campaignCode, campaign.campaignCode);
    }
    
    @Override
    public int hashCode() {
        return Objects.hash(id, campaignCode);
    }
    
    @Override
    public String toString() {
        return "Campaign{" +
                "id=" + id +
                ", campaignCode='" + campaignCode + '\'' +
                ", companyId=" + companyId +
                ", name='" + name + '\'' +
                ", status=" + status +
                ", isActive=" + isActive +
                '}';
    }
}
