package com.jeesharp.business.modules.marketing.stats.application;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.StrUtil;
import com.jeesharp.business.modules.coupon.api.MemberCouponStatsApi;
import com.jeesharp.business.modules.coupon.dto.MemberCouponStoreStatsQueryDTO;
import com.jeesharp.business.modules.coupon.vo.MemberCouponChannelCountVO;
import com.jeesharp.business.modules.coupon.vo.MemberCouponDailyCountVO;
import com.jeesharp.business.modules.marketing.stats.service.MarketingStatsService;
import com.jeesharp.business.modules.marketing.stats.vo.MarketingStatsChannelItemVO;
import com.jeesharp.business.modules.marketing.stats.vo.MarketingStatsDailyTrendItemVO;
import com.jeesharp.business.modules.marketing.stats.vo.MarketingStatsOverviewVO;
import com.jeesharp.business.modules.marketing.stats.vo.MarketingStatsQueryVO;
import com.jeesharp.business.modules.marketing.tenantExt.entity.MarketingTenantExt;
import com.jeesharp.business.modules.marketing.tenantExt.service.MarketingTenantExtService;
import com.jeesharp.business.modules.marketing.tenantExt.vo.MarketingTenantExtQueryVO;
import lombok.AllArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.util.ArrayList;
import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.TreeMap;

/**
 * 会员营销统计应用服务：编排本模块统计与 coupon-api 领券数据。
 *
 * @author jeesharp
 * @since 2026-06-25
 */
@Service
@AllArgsConstructor
@Transactional(readOnly = true)
public class MarketingStatsApplicationService {

    private final MarketingStatsService marketingStatsService;
    private final MemberCouponStatsApi memberCouponStatsApi;
    private final MarketingTenantExtService marketingTenantExtService;

    public MarketingStatsOverviewVO overview(MarketingStatsQueryVO query) {
        MarketingStatsQueryVO q = query != null ? query : new MarketingStatsQueryVO();
        String tenantId = resolveCurrentTenantId();
        q.setTenantId(tenantId);
        LocalDate endDate = q.getDateEnd() != null ? q.getDateEnd() : LocalDate.now();
        LocalDate startDate = q.getDateStart() != null ? q.getDateStart() : endDate.minusDays(29);
        LocalDateTime startDateTime = startDate.atStartOfDay();
        LocalDateTime endDateTime = endDate.atTime(LocalTime.of(23, 59, 59));

        long joinCount = marketingStatsService.countJoin(q, startDateTime, endDateTime);
        long verifyCount = marketingStatsService.countVerify(q, startDateTime, endDateTime);
        MemberCouponStoreStatsQueryDTO couponQuery = buildCouponQuery(tenantId, startDateTime, endDateTime, q.getChannelCode());
        long receiveCount = StrUtil.isNotBlank(tenantId)
                ? memberCouponStatsApi.countStoreOfflineReceive(couponQuery)
                : 0L;

        MarketingStatsOverviewVO vo = new MarketingStatsOverviewVO();
        vo.setJoinCount(joinCount);
        vo.setReceiveCount(receiveCount);
        vo.setVerifyCount(verifyCount);
        vo.setVerifyRate(calcRate(verifyCount, receiveCount));
        vo.setChannelStats(mergeChannelStats(q, startDateTime, endDateTime, tenantId));
        vo.setDailyTrend(mergeDailyTrend(q, startDateTime, endDateTime, startDate, endDate, tenantId));
        return vo;
    }

    private List<MarketingStatsChannelItemVO> mergeChannelStats(MarketingStatsQueryVO q,
                                                                LocalDateTime startDateTime,
                                                                LocalDateTime endDateTime,
                                                                String tenantId) {
        if (StrUtil.isNotBlank(q.getChannelCode())) {
            MarketingStatsChannelItemVO item = new MarketingStatsChannelItemVO();
            item.setChannelCode(q.getChannelCode());
            item.setJoinCount(marketingStatsService.countJoin(q, startDateTime, endDateTime));
            item.setVerifyCount(marketingStatsService.countVerify(q, startDateTime, endDateTime));
            MemberCouponStoreStatsQueryDTO couponQuery = buildCouponQuery(tenantId, startDateTime, endDateTime, q.getChannelCode());
            item.setReceiveCount(StrUtil.isNotBlank(tenantId)
                    ? memberCouponStatsApi.countStoreOfflineReceive(couponQuery)
                    : 0L);
            return Collections.singletonList(item);
        }

        Map<String, MarketingStatsChannelItemVO> map = new LinkedHashMap<>();
        for (MarketingStatsChannelItemVO row : marketingStatsService.channelJoin(q, startDateTime, endDateTime)) {
            map.put(row.getChannelCode(), row);
        }
        if (StrUtil.isNotBlank(tenantId)) {
            MemberCouponStoreStatsQueryDTO couponQuery = buildCouponQuery(tenantId, startDateTime, endDateTime, null);
            for (MemberCouponChannelCountVO row : memberCouponStatsApi.channelStoreOfflineReceive(couponQuery)) {
                MarketingStatsChannelItemVO item = map.computeIfAbsent(row.getChannelCode(), code -> {
                    MarketingStatsChannelItemVO vo = new MarketingStatsChannelItemVO();
                    vo.setChannelCode(code);
                    vo.setJoinCount(0L);
                    vo.setVerifyCount(0L);
                    return vo;
                });
                item.setReceiveCount(row.getCount() != null ? row.getCount() : 0L);
            }
        }
        for (MarketingStatsChannelItemVO row : marketingStatsService.channelVerify(q, startDateTime, endDateTime)) {
            MarketingStatsChannelItemVO item = map.computeIfAbsent(row.getChannelCode(), code -> {
                MarketingStatsChannelItemVO vo = new MarketingStatsChannelItemVO();
                vo.setChannelCode(code);
                vo.setJoinCount(0L);
                vo.setReceiveCount(0L);
                return vo;
            });
            item.setVerifyCount(row.getVerifyCount() != null ? row.getVerifyCount() : 0L);
        }
        for (MarketingStatsChannelItemVO item : map.values()) {
            if (item.getJoinCount() == null) {
                item.setJoinCount(0L);
            }
            if (item.getReceiveCount() == null) {
                item.setReceiveCount(0L);
            }
            if (item.getVerifyCount() == null) {
                item.setVerifyCount(0L);
            }
        }
        return new ArrayList<>(map.values());
    }

    private List<MarketingStatsDailyTrendItemVO> mergeDailyTrend(MarketingStatsQueryVO q,
                                                                 LocalDateTime startDateTime,
                                                                 LocalDateTime endDateTime,
                                                                 LocalDate startDate,
                                                                 LocalDate endDate,
                                                                 String tenantId) {
        Map<LocalDate, MarketingStatsDailyTrendItemVO> map = new TreeMap<>();
        for (LocalDate d = startDate; !d.isAfter(endDate); d = d.plusDays(1)) {
            MarketingStatsDailyTrendItemVO item = new MarketingStatsDailyTrendItemVO();
            item.setDate(d);
            item.setJoin(0L);
            item.setReceive(0L);
            item.setVerify(0L);
            map.put(d, item);
        }
        for (MarketingStatsDailyTrendItemVO row : marketingStatsService.dailyJoin(q, startDateTime, endDateTime)) {
            MarketingStatsDailyTrendItemVO item = map.get(row.getDate());
            if (item != null) {
                item.setJoin(row.getJoin() != null ? row.getJoin() : 0L);
            }
        }
        if (StrUtil.isNotBlank(tenantId)) {
            MemberCouponStoreStatsQueryDTO couponQuery = buildCouponQuery(tenantId, startDateTime, endDateTime, q.getChannelCode());
            for (MemberCouponDailyCountVO row : memberCouponStatsApi.dailyStoreOfflineReceive(couponQuery)) {
                MarketingStatsDailyTrendItemVO item = map.get(row.getDate());
                if (item != null) {
                    item.setReceive(row.getCount() != null ? row.getCount() : 0L);
                }
            }
        }
        for (MarketingStatsDailyTrendItemVO row : marketingStatsService.dailyVerify(q, startDateTime, endDateTime)) {
            MarketingStatsDailyTrendItemVO item = map.get(row.getDate());
            if (item != null) {
                item.setVerify(row.getVerify() != null ? row.getVerify() : 0L);
            }
        }
        return new ArrayList<>(map.values());
    }

    private MemberCouponStoreStatsQueryDTO buildCouponQuery(String tenantId,
                                                            LocalDateTime startDateTime,
                                                            LocalDateTime endDateTime,
                                                            String channelCode) {
        MemberCouponStoreStatsQueryDTO couponQuery = new MemberCouponStoreStatsQueryDTO();
        couponQuery.setTenantId(tenantId);
        couponQuery.setStartDateTime(startDateTime);
        couponQuery.setEndDateTime(endDateTime);
        couponQuery.setChannelCode(channelCode);
        return couponQuery;
    }

    private String resolveCurrentTenantId() {
        List<MarketingTenantExt> list = marketingTenantExtService.findList(new MarketingTenantExtQueryVO());
        if (CollUtil.isEmpty(list)) {
            return null;
        }
        return StrUtil.blankToDefault(list.get(0).getTenantId(), null);
    }

    private BigDecimal calcRate(long numerator, long denominator) {
        if (denominator <= 0) {
            return null;
        }
        return BigDecimal.valueOf(numerator)
                .multiply(BigDecimal.valueOf(100))
                .divide(BigDecimal.valueOf(denominator), 2, RoundingMode.HALF_UP);
    }
}
