package com.social.media.infrastructure.persistence.campaign;

import com.social.media.application.shared.security.AuthenticationService;
import com.social.media.domain.campaign.aggregate.Campaign;
import com.social.media.domain.campaign.repository.CampaignRepository;
import com.social.media.domain.campaign.valueobject.CampaignId;
import com.social.media.domain.campaign.valueobject.CampaignInteractionStatus;
import com.social.media.domain.campaign.valueobject.CampaignInteractionType;
import com.social.media.domain.user.valueobject.UserId;
import com.social.media.domain.socialaccount.valueobject.SocialAccountId;
import com.social.media.domain.bot.valueobject.BotId;
import org.springframework.stereotype.Repository;

import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;

/**
 * Implementation of CampaignRepository using JPA
 */
@Repository
public class CampaignRepositoryImpl implements CampaignRepository {
    
    private final CampaignJpaRepository jpaRepository;
    private final CampaignMapper mapper;
    private final AuthenticationService authenticationService;
    
    public CampaignRepositoryImpl(CampaignJpaRepository jpaRepository, CampaignMapper mapper, AuthenticationService authenticationService) {
        this.jpaRepository = jpaRepository;
        this.mapper = mapper;
        this.authenticationService = authenticationService;
    }
    
    private Long getCurrentUserId() {
        return authenticationService.getAuthenticatedUserInfo().getUserIdAsLong();
    }
    
    private Long getCurrentCompanyId() {
        return authenticationService.getAuthenticatedUserInfo().companyIdAsLong();
    }
    
    @Override
    public Campaign save(Campaign campaign) {
        CampaignJpaEntity entity = mapper.toJpaEntity(campaign);
        CampaignJpaEntity savedEntity = jpaRepository.save(entity);
        return mapper.toDomainEntity(savedEntity);
    }
    
    @Override
    public Optional<Campaign> findById(CampaignId campaignId) {
        return jpaRepository.findById(campaignId.value())
                .map(mapper::toDomainEntity);
    }
    
    @Override
    public List<Campaign> findByUserId(UserId userId) {
        return jpaRepository.findByUserIdAndCompanyId(userId.value(), getCurrentCompanyId())
                .stream()
                .map(mapper::toDomainEntity)
                .collect(Collectors.toList());
    }
    
    @Override
    public List<Campaign> findByUserIdAndStatus(UserId userId, CampaignInteractionStatus status) {
        return jpaRepository.findByUserIdAndStatusInterationAndCompanyId(userId.value(), status, getCurrentCompanyId())
                .stream()
                .map(mapper::toDomainEntity)
                .collect(Collectors.toList());
    }
    
    @Override
    public List<Campaign> findByUserIdAndInteractionType(UserId userId, CampaignInteractionType interactionType) {
        return jpaRepository.findByUserIdAndTypeInterationAndCompanyId(userId.value(), interactionType, getCurrentCompanyId())
                .stream()
                .map(mapper::toDomainEntity)
                .collect(Collectors.toList());
    }
    
    @Override
    public List<Campaign> findByBotId(BotId botId) {
        return jpaRepository.findByBotIdAndCompanyIdAndUserId(botId.value(), getCurrentCompanyId(), getCurrentUserId())
                .stream()
                .map(mapper::toDomainEntity)
                .collect(Collectors.toList());
    }
    
    @Override
    public List<Campaign> findByAccountNetworkId(SocialAccountId accountNetworkId) {
        return jpaRepository.findByAccountNetworkIdAndCompanyIdAndUserId(accountNetworkId.value(), getCurrentCompanyId(), getCurrentUserId())
                .stream()
                .map(mapper::toDomainEntity)
                .collect(Collectors.toList());
    }
    
    @Override
    public List<Campaign> findActiveCampaigns() {
        return jpaRepository.findByStatusInterationAndCompanyIdAndUserId(CampaignInteractionStatus.RUNNING, getCurrentCompanyId(), getCurrentUserId())
                .stream()
                .map(mapper::toDomainEntity)
                .collect(Collectors.toList());
    }
    
    @Override
    public List<Campaign> findScheduledForDate(LocalDate date) {
        return jpaRepository.findByDateInterationAndCompanyIdAndUserId(date, getCurrentCompanyId(), getCurrentUserId())
                .stream()
                .map(mapper::toDomainEntity)
                .collect(Collectors.toList());
    }
    
    @Override
    public List<Campaign> findInExecutionPeriod(LocalDateTime dateTime) {
        return jpaRepository.findInExecutionPeriodAndCompanyIdAndUserId(dateTime.toLocalDate(), getCurrentCompanyId(), getCurrentUserId())
                .stream()
                .map(mapper::toDomainEntity)
                .collect(Collectors.toList());
    }
    
    @Override
    public List<Campaign> findByDateRange(LocalDate startDate, LocalDate endDate) {
        return jpaRepository.findByDateRangeAndCompanyIdAndUserId(startDate, endDate, getCurrentCompanyId(), getCurrentUserId())
                .stream()
                .map(mapper::toDomainEntity)
                .collect(Collectors.toList());
    }
    
    @Override
    public List<Campaign> findByUserIdAndDateRange(UserId userId, LocalDate startDate, LocalDate endDate) {
        return jpaRepository.findByUserIdAndDateRangeAndCompanyId(userId.value(), startDate, endDate, getCurrentCompanyId())
                .stream()
                .map(mapper::toDomainEntity)
                .collect(Collectors.toList());
    }
    
    @Override
    public List<Campaign> findCampaignsToStart(LocalDateTime currentDateTime) {
        return jpaRepository.findCampaignsToStartByCompanyId(
                CampaignInteractionStatus.WAIT, 
                currentDateTime.toLocalDate(),
                getCurrentCompanyId())
                .stream()
                .map(mapper::toDomainEntity)
                .collect(Collectors.toList());
    }
    
    @Override
    public List<Campaign> findCampaignsToStop(LocalDateTime currentDateTime) {
        return jpaRepository.findCampaignsToStopByCompanyId(
                CampaignInteractionStatus.RUNNING, 
                currentDateTime.toLocalDate(),
                getCurrentCompanyId())
                .stream()
                .map(mapper::toDomainEntity)
                .collect(Collectors.toList());
    }
    
    @Override
    public boolean existsByUserIdAndName(UserId userId, String name) {
        return jpaRepository.existsByUserIdAndNameAndCompanyId(userId.value(), name, getCurrentCompanyId());
    }
    
    @Override
    public long countByUserId(UserId userId) {
        return jpaRepository.countByUserIdAndCompanyId(userId.value(), getCurrentCompanyId());
    }
    
    @Override
    public long countByUserIdAndStatus(UserId userId, CampaignInteractionStatus status) {
        return jpaRepository.countByUserIdAndStatusInterationAndCompanyId(userId.value(), status, getCurrentCompanyId());
    }
    
    @Override
    public void deleteById(CampaignId campaignId) {
        jpaRepository.deleteById(campaignId.value());
    }
    
    @Override
    public boolean existsById(CampaignId campaignId) {
        return jpaRepository.existsById(campaignId.value());
    }
}
