package com.jeesharp.business.modules.member.application;

import cn.hutool.core.util.StrUtil;
import com.jeesharp.business.modules.member.convert.MemberPointsRuleConvert;
import com.jeesharp.business.modules.member.convert.MemberPointsRuleLevelConvert;
import com.jeesharp.business.modules.member.dto.MemberPointsRuleLevelSaveItemDTO;
import com.jeesharp.business.modules.member.dto.MemberPointsRuleSaveDTO;
import com.jeesharp.business.modules.member.entity.MemberLevel;
import com.jeesharp.business.modules.member.entity.MemberPointsRule;
import com.jeesharp.business.modules.member.entity.MemberPointsRuleLevel;
import com.jeesharp.business.modules.member.enums.MemberPointsCalcTypeEnum;
import com.jeesharp.business.modules.member.enums.MemberPointsSceneEnum;
import com.jeesharp.business.modules.member.service.MemberLevelService;
import com.jeesharp.business.modules.member.service.MemberPointsRuleService;
import com.jeesharp.business.modules.member.vo.MemberLevelQueryVO;
import com.jeesharp.business.modules.member.vo.MemberPointsRuleInfoVO;
import com.jeesharp.business.modules.member.vo.MemberPointsRuleLevelItemVO;
import com.jeesharp.business.modules.member.vo.MemberPointsRuleListVO;
import com.jeesharp.business.modules.member.vo.MemberPointsRuleMetaLevelVO;
import com.jeesharp.business.modules.member.vo.MemberPointsRuleMetaOptionVO;
import com.jeesharp.business.modules.member.vo.MemberPointsRuleQueryVO;
import com.jeesharp.framework.exception.BizErrorException;
import com.jeesharp.framework.pojo.Page;
import com.jeesharp.framework.pojo.query.PageRespVO;
import lombok.AllArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * 积分规则管理端应用服务：规则 CRUD 与元数据。
 *
 * @author jeesharp
 * @since 2026-06-23
 */
@Service
@AllArgsConstructor
@Transactional(readOnly = true)
public class MemberPointsRuleManageApplicationService {

    private final MemberPointsRuleService memberPointsRuleService;
    private final MemberLevelService memberLevelService;

    public PageRespVO<MemberPointsRuleListVO> findPage(Page<MemberPointsRule> page, MemberPointsRuleQueryVO query) {
        Page<MemberPointsRule> result = memberPointsRuleService.findPage(page, query);
        return MemberPointsRuleConvert.INSTANCE.toPageRespVO(result);
    }

    public MemberPointsRuleInfoVO get(String id) {
        MemberPointsRule rule = memberPointsRuleService.getRule(id);
        if (rule == null) {
            throw new BizErrorException("积分规则不存在");
        }
        MemberPointsRuleInfoVO vo = MemberPointsRuleConvert.INSTANCE.toInfoVO(rule);
        List<MemberPointsRuleLevel> levels = memberPointsRuleService.listLevelsByRuleId(id);
        List<MemberPointsRuleLevelItemVO> items = MemberPointsRuleLevelConvert.INSTANCE.toItemVOList(levels);
        enrichLevelNames(items);
        vo.setLevelItems(items);
        return vo;
    }

    @Transactional(readOnly = false)
    public String create(MemberPointsRuleSaveDTO dto) {
        if (StrUtil.isNotBlank(dto.getId())) {
            throw new BizErrorException("新增请求不应携带主键 id");
        }
        validateSave(dto, null);
        MemberPointsRule rule = MemberPointsRuleConvert.INSTANCE.toEntity(dto);
        applyDefaults(rule);
        memberPointsRuleService.createRule(rule);
        memberPointsRuleService.replaceRuleLevels(rule.getId(), buildLevelEntities(dto.getLevelItems()));
        return rule.getId();
    }

    @Transactional(readOnly = false)
    public void update(MemberPointsRuleSaveDTO dto) {
        if (StrUtil.isBlank(dto.getId())) {
            throw new BizErrorException("更新请求必须携带主键 id");
        }
        validateSave(dto, dto.getId());
        MemberPointsRule rule = MemberPointsRuleConvert.INSTANCE.toEntity(dto);
        applyDefaults(rule);
        memberPointsRuleService.updateRule(rule);
        memberPointsRuleService.replaceRuleLevels(dto.getId(), buildLevelEntities(dto.getLevelItems()));
    }

    @Transactional(readOnly = false)
    public void delete(String ids) {
        if (StrUtil.isBlank(ids)) {
            throw new BizErrorException("请选择要删除的规则");
        }
        List<String> idList = Arrays.stream(ids.split(","))
                .map(String::trim)
                .filter(StrUtil::isNotBlank)
                .collect(Collectors.toList());
        memberPointsRuleService.batchDeleteRules(idList);
    }

    public List<MemberPointsRuleMetaOptionVO> metaScenes() {
        List<MemberPointsRuleMetaOptionVO> list = new ArrayList<>();
        for (MemberPointsSceneEnum item : MemberPointsSceneEnum.values()) {
            list.add(new MemberPointsRuleMetaOptionVO(item.getCode(), item.getDesc()));
        }
        return list;
    }

    public List<MemberPointsRuleMetaOptionVO> metaCalcTypes() {
        List<MemberPointsRuleMetaOptionVO> list = new ArrayList<>();
        for (MemberPointsCalcTypeEnum item : MemberPointsCalcTypeEnum.values()) {
            list.add(new MemberPointsRuleMetaOptionVO(item.getCode(), item.getDesc()));
        }
        return list;
    }

    public List<MemberPointsRuleMetaLevelVO> metaLevels() {
        MemberLevelQueryVO query = new MemberLevelQueryVO();
        query.setStatus(1);
        List<MemberLevel> levels = memberLevelService.findList(query);
        levels.sort(Comparator.comparing(MemberLevel::getLevelSort, Comparator.nullsLast(Integer::compareTo)));
        List<MemberPointsRuleMetaLevelVO> result = new ArrayList<>();
        for (MemberLevel level : levels) {
            MemberPointsRuleMetaLevelVO vo = new MemberPointsRuleMetaLevelVO();
            vo.setId(level.getId());
            vo.setLevelCode(level.getLevelCode());
            vo.setLevelName(level.getLevelName());
            vo.setPointsRate(level.getPointsRate());
            result.add(vo);
        }
        return result;
    }

    private void validateSave(MemberPointsRuleSaveDTO dto, String excludeId) {
        if (MemberPointsSceneEnum.fromCode(dto.getSceneCode()) == null) {
            throw new BizErrorException("场景编码无效");
        }
        if (MemberPointsCalcTypeEnum.fromCode(dto.getCalcType()) == null) {
            throw new BizErrorException("计算方式无效");
        }
        if (memberPointsRuleService.existsSceneCode(dto.getSceneCode(), excludeId)) {
            throw new BizErrorException("该场景已存在积分规则，每个场景仅允许一条规则");
        }
    }

    private void applyDefaults(MemberPointsRule rule) {
        if (rule.getBasePoints() == null) {
            rule.setBasePoints(0);
        }
        if (rule.getApplyLevelRate() == null) {
            rule.setApplyLevelRate(0);
        }
        if (rule.getValidDays() == null) {
            rule.setValidDays(0);
        }
        if (rule.getDailyLimit() == null) {
            rule.setDailyLimit(0);
        }
        if (rule.getTotalLimit() == null) {
            rule.setTotalLimit(0);
        }
    }

    private List<MemberPointsRuleLevel> buildLevelEntities(List<MemberPointsRuleLevelSaveItemDTO> items) {
        if (items == null || items.isEmpty()) {
            return List.of();
        }
        Map<String, MemberLevel> levelMap = loadLevelMap();
        List<MemberPointsRuleLevel> list = new ArrayList<>();
        for (MemberPointsRuleLevelSaveItemDTO item : items) {
            if (StrUtil.isBlank(item.getLevelId())) {
                continue;
            }
            MemberPointsRuleLevel entity = MemberPointsRuleLevelConvert.INSTANCE.fromSaveItem(item);
            MemberLevel level = levelMap.get(item.getLevelId());
            if (level != null && StrUtil.isBlank(entity.getLevelCode())) {
                entity.setLevelCode(level.getLevelCode());
            }
            if (entity.getStatus() == null) {
                entity.setStatus(1);
            }
            list.add(entity);
        }
        return list;
    }

    private Map<String, MemberLevel> loadLevelMap() {
        MemberLevelQueryVO query = new MemberLevelQueryVO();
        List<MemberLevel> levels = memberLevelService.findList(query);
        Map<String, MemberLevel> map = new HashMap<>();
        for (MemberLevel level : levels) {
            map.put(level.getId(), level);
        }
        return map;
    }

    private void enrichLevelNames(List<MemberPointsRuleLevelItemVO> items) {
        if (items == null || items.isEmpty()) {
            return;
        }
        Map<String, MemberLevel> levelMap = loadLevelMap();
        for (MemberPointsRuleLevelItemVO item : items) {
            MemberLevel level = levelMap.get(item.getLevelId());
            if (level != null) {
                item.setLevelName(level.getLevelName());
                if (StrUtil.isBlank(item.getLevelCode())) {
                    item.setLevelCode(level.getLevelCode());
                }
            }
        }
    }
}
