package com.red.circle.other.infra.gateway;

import com.red.circle.other.domain.gateway.RocketStatusGateway;
import com.red.circle.other.domain.rocket.RocketStatus;
import com.red.circle.other.domain.rocket.RocketStatusEnum;
import com.red.circle.other.infra.database.mongo.document.RocketStatusDocument;
import com.red.circle.other.infra.database.mongo.repository.RocketStatusRepository;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Component;

import java.time.LocalDate;
import java.util.List;
import java.util.stream.Collectors;

/**
 * 火箭状态Gateway实现
 *
 * @author system
 * @date 2025-01-15
 */
@Component
@RequiredArgsConstructor
public class RocketStatusGatewayImpl implements RocketStatusGateway {

    private final RocketStatusRepository rocketStatusRepository;

    @Override
    public RocketStatus findByRoomIdAndDate(Long roomId, String date) {
        return rocketStatusRepository.findByRoomIdAndDate(roomId, date)
                .map(this::toDomain)
                .orElse(null);
    }

    /**
     * 查询火箭状态（不包含贡献者列表，性能优化）
     * 用于：只需要基础信息的场景
     */
    public RocketStatus findByRoomIdAndDateWithoutContributors(Long roomId, String date) {
        return rocketStatusRepository.findByRoomIdAndDateWithoutContributors(roomId, date)
                .map(this::toDomain)
                .orElse(null);
    }

    /**
     * 查询火箭状态（只包含Top N贡献者）
     * 用于：前端展示排行榜
     */
    public RocketStatus findByRoomIdAndDateWithTopContributors(Long roomId, String date, Integer topN) {
        return rocketStatusRepository.findByRoomIdAndDateWithTopContributors(roomId, date, topN)
                .map(this::toDomain)
                .orElse(null);
    }

    @Override
    public void save(RocketStatus rocketStatus) {
        RocketStatusDocument document = toDocument(rocketStatus);
        rocketStatusRepository.save(document);
        // 回填ID
        rocketStatus.setId(document.getId());
    }

    @Override
    public List<RocketStatus> findByRoomIds(List<Long> roomIds, String date) {
        // 批量查询时不返回贡献者列表（性能优化）
        List<RocketStatusDocument> documents = rocketStatusRepository
                .findByRoomIdInAndDateWithoutContributors(roomIds, date);
        return documents.stream()
                .map(this::toDomain)
                .collect(Collectors.toList());
    }

    @Override
    public List<RocketStatus> findAllCharging(String date) {
        // 定时任务查询时不需要贡献者列表（性能优化）
        List<RocketStatusDocument> documents = rocketStatusRepository
                .findByStatusAndDateWithoutContributors(
                        RocketStatusEnum.CHARGING.getCode(), 
                        date
                );
        return documents.stream()
                .map(this::toDomain)
                .collect(Collectors.toList());
    }

    /**
     * 查询所有充能状态的火箭（包含完整贡献者列表）
     * 用于：需要保存历史记录的场景
     */
    public List<RocketStatus> findAllChargingWithContributors(String date) {
        List<RocketStatusDocument> documents = rocketStatusRepository.findByStatusAndDate(
                RocketStatusEnum.CHARGING.getCode(), 
                date
        );
        return documents.stream()
                .map(this::toDomain)
                .collect(Collectors.toList());
    }

    @Override
    public void delete(String id) {
        rocketStatusRepository.deleteById(id);
    }

    /**
     * Document转Domain
     */
    private RocketStatus toDomain(RocketStatusDocument doc) {
        RocketStatus status = new RocketStatus();
        status.setId(doc.getId());
        status.setRoomId(doc.getRoomId());
        status.setDate(doc.getDate());
        status.setLevel(com.red.circle.other.domain.rocket.RocketLevel.of(doc.getLevel()));
        status.setCurrentEnergy(doc.getCurrentEnergy());
        status.setMaxEnergy(doc.getMaxEnergy());
        status.setStatus(RocketStatusEnum.of(doc.getStatus()));
        
        // 转换贡献者（可能为null，如果使用了投影查询）
        if (doc.getContributors() != null) {
            List<com.red.circle.other.domain.rocket.RocketContributor> contributors = doc.getContributors().stream()
                    .map(c -> {
                        com.red.circle.other.domain.rocket.RocketContributor contributor = 
                                new com.red.circle.other.domain.rocket.RocketContributor();
                        contributor.setUserId(c.getUserId());
                        contributor.setUserName(c.getUserName());
                        contributor.setUserAvatar(c.getUserAvatar());
                        contributor.setEnergy(c.getEnergy());
                        contributor.setContributionRate(
                                c.getContributionRate() != null ? 
                                java.math.BigDecimal.valueOf(c.getContributionRate()) : 
                                java.math.BigDecimal.ZERO
                        );
                        contributor.setGiftCount(c.getGiftCount());
                        contributor.setFirstContributeTime(c.getFirstContributeTime());
                        contributor.setLastContributeTime(c.getLastContributeTime());
                        return contributor;
                    })
                    .collect(Collectors.toList());
            status.setContributors(contributors);
        }
        
        status.setLaunchTime(doc.getLaunchTime());
        status.setClaimExpireTime(doc.getClaimExpireTime());
        status.setClaimCount(doc.getClaimCount());
        status.setCreatedAt(doc.getCreatedAt());
        status.setUpdatedAt(doc.getUpdatedAt());
        return status;
    }

    /**
     * Domain转Document
     */
    private RocketStatusDocument toDocument(RocketStatus status) {
        RocketStatusDocument doc = new RocketStatusDocument();
        doc.setId(status.getId());
        doc.setRoomId(status.getRoomId());
        doc.setDate(status.getDate());
        doc.setLevel(status.getLevel().getLevel());
        doc.setCurrentEnergy(status.getCurrentEnergy());
        doc.setMaxEnergy(status.getMaxEnergy());
        doc.setStatus(status.getStatus().getCode());
        
        // 转换贡献者
        if (status.getContributors() != null) {
            List<RocketStatusDocument.ContributorDoc> contributors = status.getContributors().stream()
                    .map(c -> {
                        RocketStatusDocument.ContributorDoc doc1 = new RocketStatusDocument.ContributorDoc();
                        doc1.setUserId(c.getUserId());
                        doc1.setUserName(c.getUserName());
                        doc1.setUserAvatar(c.getUserAvatar());
                        doc1.setEnergy(c.getEnergy());
                        doc1.setContributionRate(
                                c.getContributionRate() != null ? 
                                c.getContributionRate().doubleValue() : 
                                0.0
                        );
                        doc1.setGiftCount(c.getGiftCount());
                        doc1.setFirstContributeTime(c.getFirstContributeTime());
                        doc1.setLastContributeTime(c.getLastContributeTime());
                        return doc1;
                    })
                    .collect(Collectors.toList());
            doc.setContributors(contributors);
        }
        
        doc.setLaunchTime(status.getLaunchTime());
        doc.setClaimExpireTime(status.getClaimExpireTime());
        doc.setClaimCount(status.getClaimCount());
        doc.setCreatedAt(status.getCreatedAt());
        doc.setUpdatedAt(status.getUpdatedAt());
        return doc;
    }

    @Override
    public List<RocketStatus> listByDate(String date) {
        List<RocketStatusDocument> documents = rocketStatusRepository.findAllByDate(date);
        return documents.stream()
                .map(this::toDomain)
                .collect(Collectors.toList());
    }

}
