package com.social.media.infrastructure.persistence.analytics.mapper;

import com.social.media.domain.analytics.aggregate.AccountMetrics;
import com.social.media.domain.analytics.valueobject.*;
import com.social.media.domain.company.valueobject.CompanyId;
import com.social.media.domain.socialaccount.valueobject.SocialAccountId;
import com.social.media.infrastructure.persistence.analytics.entity.*;
import org.springframework.stereotype.Component;

import java.math.BigDecimal;
import java.util.EnumMap;
import java.util.HashMap;
import java.util.Map;

/**
 * Mapper for AccountMetrics domain aggregate to AccountMetricsEntity and vice versa
 */
@Component
public class AccountMetricsEntityMapper {
    
    /**
     * Converts domain AccountMetrics to AccountMetricsEntity
     */
    public AccountMetricsEntity toEntity(AccountMetrics accountMetrics) {
        if (accountMetrics == null) {
            return null;
        }
        
        AccountMetricsEntity entity = new AccountMetricsEntity();
        entity.setId(accountMetrics.getId().value());
        entity.setCompanyId(accountMetrics.getCompanyId().value());
        entity.setSocialAccountId(accountMetrics.getSocialAccountId().value());
        entity.setPeriod(mapTimePeriod(accountMetrics.getPeriod()));
        entity.setPeriodStart(accountMetrics.getPeriodStart());
        entity.setPeriodEnd(accountMetrics.getPeriodEnd());
        entity.setMetricValues(convertMetricsToEntity(accountMetrics.getMetrics()));
        entity.setCollectedAt(accountMetrics.getCollectedAt());
        entity.setCreatedAt(accountMetrics.getCreatedAt());
        entity.setUpdatedAt(accountMetrics.getUpdatedAt());
        
        return entity;
    }
    
    /**
     * Converts AccountMetricsEntity to domain AccountMetrics
     */
    public AccountMetrics toDomain(AccountMetricsEntity entity) {
        if (entity == null) {
            return null;
        }
        
        Map<MetricType, MetricValue> metrics = convertMetricsToDomain(entity.getMetricValues());
        
        return new AccountMetrics(
            AccountMetricsId.of(entity.getId()),
            CompanyId.of(entity.getCompanyId()),
            SocialAccountId.of(entity.getSocialAccountId()),
            mapTimePeriod(entity.getPeriod()),
            entity.getPeriodStart(),
            entity.getPeriodEnd(),
            metrics,
            entity.getCollectedAt(),
            entity.getCreatedAt(),
            entity.getUpdatedAt()
        );
    }
    
    /**
     * Maps domain TimePeriod to entity TimePeriodEntity
     */
    private TimePeriodEntity mapTimePeriod(TimePeriod timePeriod) {
        if (timePeriod == null) {
            return null;
        }
        
        return switch (timePeriod) {
            case HOURLY -> TimePeriodEntity.HOURLY;
            case DAILY -> TimePeriodEntity.DAILY;
            case WEEKLY -> TimePeriodEntity.WEEKLY;
            case MONTHLY -> TimePeriodEntity.MONTHLY;
            case QUARTERLY -> TimePeriodEntity.QUARTERLY;
            case YEARLY -> TimePeriodEntity.YEARLY;
        };
    }
    
    /**
     * Maps entity TimePeriodEntity to domain TimePeriod
     */
    private TimePeriod mapTimePeriod(TimePeriodEntity timePeriodEntity) {
        if (timePeriodEntity == null) {
            return null;
        }
        
        return switch (timePeriodEntity) {
            case HOURLY -> TimePeriod.HOURLY;
            case DAILY -> TimePeriod.DAILY;
            case WEEKLY -> TimePeriod.WEEKLY;
            case MONTHLY -> TimePeriod.MONTHLY;
            case QUARTERLY -> TimePeriod.QUARTERLY;
            case YEARLY -> TimePeriod.YEARLY;
        };
    }
    
    /**
     * Maps domain MetricType to entity MetricTypeEntity
     */
    private MetricTypeEntity mapMetricType(MetricType metricType) {
        if (metricType == null) {
            return null;
        }
        
        return switch (metricType) {
            case FOLLOWERS -> MetricTypeEntity.FOLLOWERS;
            case FOLLOWING -> MetricTypeEntity.FOLLOWING;
            case POSTS -> MetricTypeEntity.POSTS;
            case LIKES -> MetricTypeEntity.LIKES;
            case COMMENTS -> MetricTypeEntity.COMMENTS;
            case SHARES -> MetricTypeEntity.SHARES;
            case VIEWS -> MetricTypeEntity.VIEWS;
            case REACH -> MetricTypeEntity.REACH;
            case ENGAGEMENT_RATE -> MetricTypeEntity.ENGAGEMENT_RATE;
            case CLICK_THROUGH_RATE -> MetricTypeEntity.CLICK_THROUGH_RATE;
            case SAVES -> MetricTypeEntity.SAVES;
            case PROFILE_VISITS -> MetricTypeEntity.PROFILE_VISITS;
            case WEBSITE_CLICKS -> MetricTypeEntity.WEBSITE_CLICKS;
            case EMAIL_CONTACTS -> MetricTypeEntity.EMAIL_CONTACTS;
            case PHONE_CONTACTS -> MetricTypeEntity.PHONE_CONTACTS;
            case MENTIONS -> MetricTypeEntity.MENTIONS;
            case HASHTAG_PERFORMANCE -> MetricTypeEntity.HASHTAG_PERFORMANCE;
            case STORY_VIEWS -> MetricTypeEntity.STORY_VIEWS;
            case REEL_PLAYS -> MetricTypeEntity.REEL_PLAYS;
            case LIVE_VIEWERS -> MetricTypeEntity.LIVE_VIEWERS;
        };
    }
    
    /**
     * Maps entity MetricTypeEntity to domain MetricType
     */
    private MetricType mapMetricType(MetricTypeEntity metricTypeEntity) {
        if (metricTypeEntity == null) {
            return null;
        }
        
        return switch (metricTypeEntity) {
            case FOLLOWERS -> MetricType.FOLLOWERS;
            case FOLLOWING -> MetricType.FOLLOWING;
            case POSTS -> MetricType.POSTS;
            case LIKES -> MetricType.LIKES;
            case COMMENTS -> MetricType.COMMENTS;
            case SHARES -> MetricType.SHARES;
            case VIEWS -> MetricType.VIEWS;
            case REACH -> MetricType.REACH;
            case ENGAGEMENT_RATE -> MetricType.ENGAGEMENT_RATE;
            case CLICK_THROUGH_RATE -> MetricType.CLICK_THROUGH_RATE;
            case SAVES -> MetricType.SAVES;
            case PROFILE_VISITS -> MetricType.PROFILE_VISITS;
            case WEBSITE_CLICKS -> MetricType.WEBSITE_CLICKS;
            case EMAIL_CONTACTS -> MetricType.EMAIL_CONTACTS;
            case PHONE_CONTACTS -> MetricType.PHONE_CONTACTS;
            case MENTIONS -> MetricType.MENTIONS;
            case HASHTAG_PERFORMANCE -> MetricType.HASHTAG_PERFORMANCE;
            case STORY_VIEWS -> MetricType.STORY_VIEWS;
            case REEL_PLAYS -> MetricType.REEL_PLAYS;
            case LIVE_VIEWERS -> MetricType.LIVE_VIEWERS;
        };
    }
    
    /**
     * Converts domain metrics map to entity format
     */
    private Map<MetricTypeEntity, BigDecimal> convertMetricsToEntity(Map<MetricType, MetricValue> domainMetrics) {
        if (domainMetrics == null) {
            return new HashMap<>();
        }
        
        Map<MetricTypeEntity, BigDecimal> entityMetrics = new HashMap<>();
        for (Map.Entry<MetricType, MetricValue> entry : domainMetrics.entrySet()) {
            MetricTypeEntity entityKey = mapMetricType(entry.getKey());
            BigDecimal entityValue = entry.getValue() != null ? entry.getValue().value() : BigDecimal.ZERO;
            entityMetrics.put(entityKey, entityValue);
        }
        return entityMetrics;
    }
    
    /**
     * Converts entity metrics map to domain format
     */
    private Map<MetricType, MetricValue> convertMetricsToDomain(Map<MetricTypeEntity, BigDecimal> entityMetrics) {
        if (entityMetrics == null) {
            return new EnumMap<>(MetricType.class);
        }
        
        Map<MetricType, MetricValue> domainMetrics = new EnumMap<>(MetricType.class);
        for (Map.Entry<MetricTypeEntity, BigDecimal> entry : entityMetrics.entrySet()) {
            MetricType domainKey = mapMetricType(entry.getKey());
            MetricValue domainValue = MetricValue.of(entry.getValue(), domainKey);
            domainMetrics.put(domainKey, domainValue);
        }
        return domainMetrics;
    }
}
