package com.social.media.domain.analytics.aggregate;

import com.social.media.domain.analytics.valueobject.*;
import com.social.media.domain.company.valueobject.CompanyId;
import com.social.media.domain.shared.exception.BusinessRuleViolationException;
import com.social.media.domain.shared.kernel.AggregateRoot;

import java.time.LocalDateTime;
import java.util.Map;
import java.util.HashMap;

/**
 * AnalyticsReport aggregate representing consolidated analytics reports
 */
public class AnalyticsReport extends AggregateRoot<AnalyticsId> {
    
    private CompanyId companyId;
    private ReportType reportType;
    private MetricType metricType;
    private LocalDateTime periodStart;
    private LocalDateTime periodEnd;
    private Map<String, Object> data;
    private String title;
    private String description;
    private LocalDateTime generatedAt;
    private LocalDateTime createdAt;
    private LocalDateTime updatedAt;
    
    // Constructor for new report
    public AnalyticsReport(CompanyId companyId, ReportType reportType, MetricType metricType,
                          LocalDateTime periodStart, LocalDateTime periodEnd, 
                          String title, String description) {
        super(AnalyticsId.generate());
        this.companyId = validateCompanyId(companyId);
        this.reportType = validateReportType(reportType);
        this.metricType = metricType; // Can be null for multi-metric reports
        this.periodStart = validatePeriodStart(periodStart);
        this.periodEnd = validatePeriodEnd(periodEnd, periodStart);
        this.title = validateTitle(title);
        this.description = description;
        this.data = new HashMap<>();
        this.generatedAt = LocalDateTime.now();
        this.createdAt = LocalDateTime.now();
        this.updatedAt = LocalDateTime.now();
    }
    
    // Constructor for existing report
    public AnalyticsReport(AnalyticsId id, CompanyId companyId, ReportType reportType, MetricType metricType,
                          LocalDateTime periodStart, LocalDateTime periodEnd, Map<String, Object> data,
                          String title, String description, LocalDateTime generatedAt,
                          LocalDateTime createdAt, LocalDateTime updatedAt) {
        super(id);
        this.companyId = companyId;
        this.reportType = reportType;
        this.metricType = metricType;
        this.periodStart = periodStart;
        this.periodEnd = periodEnd;
        this.data = data != null ? new HashMap<>(data) : new HashMap<>();
        this.title = title;
        this.description = description;
        this.generatedAt = generatedAt;
        this.createdAt = createdAt;
        this.updatedAt = updatedAt;
    }
    
    // Business methods
    public void updateData(Map<String, Object> newData) {
        if (newData == null) {
            throw new BusinessRuleViolationException("Report data cannot be null");
        }
        
        this.data.clear();
        this.data.putAll(newData);
        this.updatedAt = LocalDateTime.now();
    }
    
    public void addDataEntry(String key, Object value) {
        if (key == null || key.trim().isEmpty()) {
            throw new BusinessRuleViolationException("Data key cannot be null or empty");
        }
        
        this.data.put(key, value);
        this.updatedAt = LocalDateTime.now();
    }
    
    public void removeDataEntry(String key) {
        if (key != null) {
            this.data.remove(key);
            this.updatedAt = LocalDateTime.now();
        }
    }
    
    public void updateDescription(String newDescription) {
        this.description = newDescription;
        this.updatedAt = LocalDateTime.now();
    }
    
    public void markAsRegenerated() {
        this.generatedAt = LocalDateTime.now();
        this.updatedAt = LocalDateTime.now();
    }
    
    // Query methods
    public Object getDataEntry(String key) {
        return data.get(key);
    }
    
    public boolean hasDataEntry(String key) {
        return data.containsKey(key);
    }
    
    public boolean isEmpty() {
        return data.isEmpty();
    }
    
    public int getDataSize() {
        return data.size();
    }
    
    public boolean belongsToCompany(CompanyId companyId) {
        return this.companyId.equals(companyId);
    }
    
    public boolean isRecentlyGenerated(int hours) {
        return this.generatedAt.isAfter(LocalDateTime.now().minusHours(hours));
    }
    
    public boolean isForPeriod(LocalDateTime start, LocalDateTime end) {
        return this.periodStart.equals(start) && this.periodEnd.equals(end);
    }
    
    public boolean isOfType(ReportType type) {
        return this.reportType.equals(type);
    }
    
    public boolean isMetricSpecific() {
        return this.metricType != null;
    }
    
    public long getPeriodDurationInDays() {
        return java.time.Duration.between(periodStart, periodEnd).toDays();
    }
    
    // Validation methods
    private CompanyId validateCompanyId(CompanyId companyId) {
        if (companyId == null) {
            throw new BusinessRuleViolationException("Company ID is required");
        }
        return companyId;
    }
    
    private ReportType validateReportType(ReportType reportType) {
        if (reportType == null) {
            throw new BusinessRuleViolationException("Report type is required");
        }
        return reportType;
    }
    
    private LocalDateTime validatePeriodStart(LocalDateTime periodStart) {
        if (periodStart == null) {
            throw new BusinessRuleViolationException("Period start is required");
        }
        return periodStart;
    }
    
    private LocalDateTime validatePeriodEnd(LocalDateTime periodEnd, LocalDateTime periodStart) {
        if (periodEnd == null) {
            throw new BusinessRuleViolationException("Period end is required");
        }
        if (!periodEnd.isAfter(periodStart)) {
            throw new BusinessRuleViolationException("Period end must be after period start");
        }
        return periodEnd;
    }
    
    private String validateTitle(String title) {
        if (title == null || title.trim().isEmpty()) {
            throw new BusinessRuleViolationException("Report title is required");
        }
        if (title.trim().length() > 200) {
            throw new BusinessRuleViolationException("Report title cannot exceed 200 characters");
        }
        return title.trim();
    }
    
    // Getters
    public CompanyId getCompanyId() { return companyId; }
    public ReportType getReportType() { return reportType; }
    public MetricType getMetricType() { return metricType; }
    public LocalDateTime getPeriodStart() { return periodStart; }
    public LocalDateTime getPeriodEnd() { return periodEnd; }
    public Map<String, Object> getData() { return new HashMap<>(data); }
    public String getTitle() { return title; }
    public String getDescription() { return description; }
    public LocalDateTime getGeneratedAt() { return generatedAt; }
    public LocalDateTime getCreatedAt() { return createdAt; }
    public LocalDateTime getUpdatedAt() { return updatedAt; }
}
