package com.social.media.infrastructure.persistence.bot.mapper;

import com.social.media.domain.bot.aggregate.Bot;
import com.social.media.domain.bot.valueobject.*;
import com.social.media.domain.company.valueobject.CompanyId;
import com.social.media.domain.socialaccount.valueobject.SocialAccountId;
import com.social.media.domain.user.valueobject.UserId;
import com.social.media.infrastructure.persistence.bot.entity.*;
import org.springframework.stereotype.Component;

import java.time.LocalTime;
import java.util.*;
import java.util.stream.Collectors;

/**
 * Mapper for Bot domain aggregate to BotEntity and vice versa
 */
@Component
public class BotEntityMapper {
    
    /**
     * Converts domain Bot to BotEntity
     */
    public BotEntity toEntity(Bot bot) {
        if (bot == null) {
            return null;
        }
        
        BotEntity entity = new BotEntity();
        entity.setId(bot.getId().value());
        entity.setCompanyId(bot.getCompanyId().value());
        entity.setCreatedBy(bot.getCreatedBy().value());
        entity.setName(bot.getName());
        entity.setDescription(bot.getDescription());
        entity.setBotType(mapBotType(bot.getBotType()));
        entity.setStatus(mapBotStatus(bot.getStatus()));
        
        // Map configuration
        BotConfiguration config = bot.getConfiguration();
        if (config != null) {
            entity.setConfigurationSettings(convertSettingsToEntity(config.settings()));
            entity.setMaxActionsPerHour(config.maxActionsPerHour());
            entity.setMaxActionsPerDay(config.maxActionsPerDay());
            entity.setStartTime(config.startTime());
            entity.setEndTime(config.endTime());
            entity.setTargetHashtags(new HashSet<>(config.targetHashtags()));
            entity.setExcludeKeywords(new HashSet<>(config.excludeKeywords()));
            entity.setRespectRateLimits(config.respectRateLimits());
            entity.setDelayBetweenActions(config.delayBetweenActions());
        }
        
        // Map target relationships
        entity.setTargetSocialAccountIds(
            bot.getTargetSocialAccounts().stream()
                .map(id -> id.value())
                .collect(Collectors.toSet())
        );
        
        entity.setTargetUserListIds(
            bot.getTargetUserLists().stream()
                .map(id -> id.value())
                .collect(Collectors.toSet())
        );
        
        // Map execution tracking
        entity.setTotalExecutions(bot.getTotalExecutions());
        entity.setSuccessfulExecutions(bot.getSuccessfulExecutions());
        entity.setFailedExecutions(bot.getFailedExecutions());
        entity.setLastExecutionAt(bot.getLastExecutionAt());
        entity.setNextExecutionAt(bot.getNextExecutionAt());
        
        // Map scheduling - using default values for now since Bot doesn't have these fields
        entity.setScheduled(false);
        entity.setScheduleEnabled(false);
        entity.setCronExpression(null);
        
        // Map audit fields
        entity.setCreatedAt(bot.getCreatedAt());
        entity.setUpdatedAt(bot.getUpdatedAt());
        entity.setVersion(null); // Bot doesn't have version field currently
        
        return entity;
    }
    
    /**
     * Converts BotEntity to domain Bot
     */
    public Bot toDomain(BotEntity entity) {
        if (entity == null) {
            return null;
        }
        
        // Convert configuration
        BotConfiguration configuration = null;
        if (entity.getMaxActionsPerHour() != null || entity.getMaxActionsPerDay() != null) {
            configuration = new BotConfiguration(
                convertSettingsToDomain(entity.getConfigurationSettings()),
                entity.getMaxActionsPerHour() != null ? entity.getMaxActionsPerHour() : 0,
                entity.getMaxActionsPerDay() != null ? entity.getMaxActionsPerDay() : 0,
                entity.getStartTime() != null ? entity.getStartTime() : LocalTime.of(9, 0),
                entity.getEndTime() != null ? entity.getEndTime() : LocalTime.of(18, 0),
                entity.getTargetHashtags() != null ? new ArrayList<>(entity.getTargetHashtags()) : new ArrayList<>(),
                entity.getExcludeKeywords() != null ? new ArrayList<>(entity.getExcludeKeywords()) : new ArrayList<>(),
                entity.getRespectRateLimits() != null ? entity.getRespectRateLimits() : true,
                entity.getDelayBetweenActions() != null ? entity.getDelayBetweenActions() : 30
            );
        }
        
        // Convert target relationships
        Set<SocialAccountId> targetSocialAccounts = entity.getTargetSocialAccountIds() != null 
            ? entity.getTargetSocialAccountIds().stream()
                .map(SocialAccountId::of)
                .collect(Collectors.toSet())
            : new HashSet<>();
            
        Set<UserListId> targetUserLists = entity.getTargetUserListIds() != null
            ? entity.getTargetUserListIds().stream()
                .map(UserListId::of)
                .collect(Collectors.toSet())
            : new HashSet<>();
        
        // Use the existing Bot constructor for reconstitution
        return new Bot(
            BotId.of(entity.getId()),
            CompanyId.of(entity.getCompanyId()),
            UserId.of(entity.getCreatedBy()),
            entity.getName(),
            entity.getDescription(),
            mapBotType(entity.getBotType()),
            mapBotStatus(entity.getStatus()),
            configuration,
            targetSocialAccounts,
            targetUserLists,
            entity.getLastExecutionAt(),
            entity.getNextExecutionAt(),
            entity.getTotalExecutions() != null ? entity.getTotalExecutions() : 0,
            entity.getSuccessfulExecutions() != null ? entity.getSuccessfulExecutions() : 0,
            entity.getFailedExecutions() != null ? entity.getFailedExecutions() : 0,
            entity.getCreatedAt(),
            entity.getUpdatedAt()
        );
    }
    
    /**
     * Maps domain BotType to entity BotTypeEntity
     */
    private BotTypeEntity mapBotType(BotType botType) {
        if (botType == null) {
            return null;
        }
        
        return switch (botType) {
            case FOLLOWER -> BotTypeEntity.FOLLOWER;
            case LIKER -> BotTypeEntity.LIKER;
            case COMMENTER -> BotTypeEntity.COMMENTER;
            case SCHEDULER -> BotTypeEntity.SCHEDULER;
            case ENGAGEMENT -> BotTypeEntity.ENGAGEMENT;
            case GROWTH -> BotTypeEntity.GROWTH;
            case ANALYTICS -> BotTypeEntity.ANALYTICS;
            case HASHTAG_TRACKER -> BotTypeEntity.HASHTAG_TRACKER;
            case DM_RESPONDER -> BotTypeEntity.DM_RESPONDER;
            case CONTENT_CURATOR -> BotTypeEntity.CONTENT_CURATOR;
        };
    }
    
    /**
     * Maps entity BotTypeEntity to domain BotType
     */
    private BotType mapBotType(BotTypeEntity botTypeEntity) {
        if (botTypeEntity == null) {
            return null;
        }
        
        return switch (botTypeEntity) {
            case FOLLOWER -> BotType.FOLLOWER;
            case LIKER -> BotType.LIKER;
            case COMMENTER -> BotType.COMMENTER;
            case SCHEDULER -> BotType.SCHEDULER;
            case ENGAGEMENT -> BotType.ENGAGEMENT;
            case GROWTH -> BotType.GROWTH;
            case ANALYTICS -> BotType.ANALYTICS;
            case HASHTAG_TRACKER -> BotType.HASHTAG_TRACKER;
            case DM_RESPONDER -> BotType.DM_RESPONDER;
            case CONTENT_CURATOR -> BotType.CONTENT_CURATOR;
        };
    }
    
    /**
     * Maps domain BotStatus to entity BotStatusEntity
     */
    private BotStatusEntity mapBotStatus(BotStatus botStatus) {
        if (botStatus == null) {
            return null;
        }
        
        return switch (botStatus) {
            case ACTIVE -> BotStatusEntity.ACTIVE;
            case INACTIVE -> BotStatusEntity.INACTIVE;
            case RUNNING -> BotStatusEntity.RUNNING;
            case PAUSED -> BotStatusEntity.PAUSED;
            case ERROR -> BotStatusEntity.ERROR;
            case COMPLETED -> BotStatusEntity.COMPLETED;
            case CANCELLED -> BotStatusEntity.CANCELLED;
        };
    }
    
    /**
     * Maps entity BotStatusEntity to domain BotStatus
     */
    private BotStatus mapBotStatus(BotStatusEntity botStatusEntity) {
        if (botStatusEntity == null) {
            return null;
        }
        
        return switch (botStatusEntity) {
            case ACTIVE -> BotStatus.ACTIVE;
            case INACTIVE -> BotStatus.INACTIVE;
            case RUNNING -> BotStatus.RUNNING;
            case PAUSED -> BotStatus.PAUSED;
            case ERROR -> BotStatus.ERROR;
            case COMPLETED -> BotStatus.COMPLETED;
            case CANCELLED -> BotStatus.CANCELLED;
        };
    }
    
    /**
     * Converts configuration settings map from domain to entity format
     */
    private Map<String, String> convertSettingsToEntity(Map<String, Object> domainSettings) {
        if (domainSettings == null) {
            return new HashMap<>();
        }
        
        Map<String, String> entitySettings = new HashMap<>();
        for (Map.Entry<String, Object> entry : domainSettings.entrySet()) {
            Object value = entry.getValue();
            if (value != null) {
                entitySettings.put(entry.getKey(), value.toString());
            }
        }
        return entitySettings;
    }
    
    /**
     * Converts configuration settings map from entity to domain format
     */
    private Map<String, Object> convertSettingsToDomain(Map<String, String> entitySettings) {
        if (entitySettings == null) {
            return new HashMap<>();
        }
        
        Map<String, Object> domainSettings = new HashMap<>();
        for (Map.Entry<String, String> entry : entitySettings.entrySet()) {
            String value = entry.getValue();
            if (value != null) {
                // Try to convert to appropriate type
                Object convertedValue = convertStringToObject(value);
                domainSettings.put(entry.getKey(), convertedValue);
            }
        }
        return domainSettings;
    }
    
    /**
     * Attempts to convert string value to appropriate object type
     */
    private Object convertStringToObject(String value) {
        if (value == null || value.trim().isEmpty()) {
            return value;
        }
        
        // Try boolean
        if ("true".equalsIgnoreCase(value) || "false".equalsIgnoreCase(value)) {
            return Boolean.valueOf(value);
        }
        
        // Try integer
        try {
            return Integer.valueOf(value);
        } catch (NumberFormatException e) {
            // Not an integer
        }
        
        // Try double
        try {
            return Double.valueOf(value);
        } catch (NumberFormatException e) {
            // Not a double
        }
        
        // Return as string
        return value;
    }
}
