package com.cool.store.service.config.impl;

import com.cool.store.dao.config.ConfigItemCategoryDAO;
import com.cool.store.dao.config.ConfigItemDAO;
import com.cool.store.dao.config.ConfigOptionDAO;
import com.cool.store.dao.dict.SysDictTableDAO;
import com.cool.store.dao.store.StoreTypeOptionDAO;
import com.cool.store.entity.config.ConfigOptionDO;
import com.cool.store.enums.ErrorCodeEnum;
import com.cool.store.exception.ServiceException;
import com.cool.store.request.config.ConfigOptionQueryRequest;
import com.cool.store.request.config.ConfigOptionUpdateRequest;
import com.cool.store.request.dict.DictColumnQueryRequest;
import com.cool.store.service.config.ConfigOptionService;
import com.cool.store.service.dict.DictColumnService;
import com.cool.store.utils.BeanUtil;
import com.cool.store.utils.UUIDUtils;
import com.cool.store.vo.config.*;
import com.cool.store.vo.dict.DictColumnVO;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import lombok.RequiredArgsConstructor;
import org.apache.commons.collections4.CollectionUtils;
import org.springframework.stereotype.Service;

import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;

@Service
@RequiredArgsConstructor
public class ConfigOptionServiceImpl implements ConfigOptionService {

    private final ConfigOptionDAO configOptionDAO;
    private final StoreTypeOptionDAO storeTypeOptionDAO;
    private final DictColumnService dictColumnService;
    private final SysDictTableDAO dictTableInfoDAO;
    private final ConfigItemCategoryDAO configItemCategoryDAO;
    private final ConfigItemDAO configItemDAO;

    @Override
    public Boolean add(ConfigOptionUpdateRequest request) {
        if (request.getSortOrder() != null && configOptionDAO.existsSortOrder(request.getSortOrder(), null)) {
            throw new ServiceException(ErrorCodeEnum.CURRENT_BRAND_SORT_NUMBER_EXIST);
        }

        ConfigOptionDO entity = BeanUtil.toBean(request, ConfigOptionDO.class);
        entity.setOptionCode(UUIDUtils.get8UUID());
        return configOptionDAO.insertSelective(entity);
    }

    @Override
    public Boolean update(ConfigOptionUpdateRequest request) {
        if (request.getSortOrder() != null) {
            ConfigOptionDO old = configOptionDAO.getById(request.getId());
            boolean sortChanged = old == null || old.getSortOrder() == null || !old.getSortOrder().equals(request.getSortOrder());
            if (sortChanged && configOptionDAO.existsSortOrder(request.getSortOrder(), request.getId())) {
                throw new ServiceException(ErrorCodeEnum.CURRENT_BRAND_SORT_NUMBER_EXIST);
            }
        }
        ConfigOptionDO entity = BeanUtil.toBean(request, ConfigOptionDO.class);
        return configOptionDAO.updateSelective(entity);
    }

    @Override
    public PageInfo<ConfigOptionVO> queryPage(ConfigOptionQueryRequest request) {
        PageHelper.startPage(request.getPageNum(), request.getPageSize());
        List<ConfigOptionDO> list = configOptionDAO.query(request.getCategoryCode(), request.getItemCode(),
                request.getActive(), request.getOptionName(),request.getExpenseTypeCode());
        return BeanUtil.toPage(new PageInfo<>(list), ConfigOptionVO.class);
    }



    @Override
    public List<ConfigOptionTreeVO> listActiveTree() {
        // 1) 查询配置类型表：决定第一层顺序
        List<ConfigItemCategoryBaseInfoVO> typeDictList = configItemCategoryDAO.queryAllList();

        // 2) 查询配置项表：决定第二层顺序 & 名称
        List<ConfigItemVO> itemDictList = configItemDAO.queryByCondition("", "", null, 1);
        Map<String, ConfigItemVO> itemDictMap = itemDictList.stream()
                .filter(v -> v.getItemCode() != null)
                .collect(Collectors.toMap(ConfigItemVO::getItemCode, Function.identity(), (a, b) -> a));

        // 3) 一次性查询所有激活的配置选项（可选模糊名称）
        List<ConfigOptionDO> options = configOptionDAO.query(null, null, 1, null,null);
        if (CollectionUtils.isEmpty(options)) {
            return Collections.emptyList();
        }

        // 4) 按 categoryCode -> itemCode 分组
        Map<String, Map<String, List<ConfigOptionDO>>> groupMap = options.stream()
                .filter(v -> Boolean.TRUE.equals(v.getActive()))
                .collect(Collectors.groupingBy(
                        ConfigOptionDO::getCategoryCode,
                        Collectors.groupingBy(ConfigOptionDO::getItemCode)
                ));

        // 5) 组装三层结构：第一层按 type 字典顺序；第二层按 item 字典顺序；第三层按 sortOrder
        List<ConfigOptionTreeVO> result = new ArrayList<>();
        for (ConfigItemCategoryBaseInfoVO typeDict : typeDictList) {
            String categoryCode = typeDict.getCategoryCode();
            Map<String, List<ConfigOptionDO>> itemOptionsMap = groupMap.get(categoryCode);
            if (itemOptionsMap == null || itemOptionsMap.isEmpty()) {
                continue;
            }

            ConfigOptionTreeVO typeVO = new ConfigOptionTreeVO();
            typeVO.setCategoryCode(categoryCode);
            typeVO.setCategoryName(typeDict.getCategoryName());

            List<ConfigOptionTreeVO.ConfigItemVO> itemVOList = new ArrayList<>();
            for (ConfigItemVO itemDict : itemDictList) {
                String itemCode = itemDict.getItemCode();
                List<ConfigOptionDO> optionList = itemOptionsMap.get(itemCode);
                if (CollectionUtils.isEmpty(optionList)) {
                    continue;
                }

                ConfigOptionTreeVO.ConfigItemVO itemVO = new ConfigOptionTreeVO.ConfigItemVO();
                itemVO.setItemCode(itemCode);
                itemVO.setItemName(itemDict.getItemName());

                List<ConfigOptionVO> optionVOList = optionList.stream()
                        .sorted(Comparator.comparing(ConfigOptionDO::getSortOrder, Comparator.nullsLast(Integer::compareTo)))
                        .map(v -> BeanUtil.toBean(v, ConfigOptionVO.class))
                        .collect(Collectors.toList());
                itemVO.setOptions(optionVOList);
                itemVOList.add(itemVO);
            }

            // 如果 itemCode 没在字典表11里（比如数据脏了），补在最后
            Set<String> knownItemCodes = itemDictMap.keySet();
            List<String> unknownItemCodes = itemOptionsMap.keySet().stream()
                    .filter(v -> v != null && !knownItemCodes.contains(v))
                    .sorted()
                    .collect(Collectors.toList());
            for (String itemCode : unknownItemCodes) {
                List<ConfigOptionDO> optionList = itemOptionsMap.get(itemCode);
                if (CollectionUtils.isEmpty(optionList)) {
                    continue;
                }
                ConfigOptionTreeVO.ConfigItemVO itemVO = new ConfigOptionTreeVO.ConfigItemVO();
                itemVO.setItemCode(itemCode);
                itemVO.setItemName(itemCode);
                List<ConfigOptionVO> optionVOList = optionList.stream()
                        .sorted(Comparator.comparing(ConfigOptionDO::getSortOrder, Comparator.nullsLast(Integer::compareTo)))
                        .map(v -> BeanUtil.toBean(v, ConfigOptionVO.class))
                        .collect(Collectors.toList());
                itemVO.setOptions(optionVOList);
                itemVOList.add(itemVO);
            }

            if (CollectionUtils.isEmpty(itemVOList)) {
                continue;
            }
            typeVO.setItems(itemVOList);
            result.add(typeVO);
        }

        return result;
    }

    private List<DictColumnVO> listOpenDictColumns(Long dictTableId) {
        DictColumnQueryRequest dictReq = DictColumnQueryRequest.builder()
                .dictTableId(dictTableId)
                .openStatus(1)
                .build();
        dictReq.setPageSize(10000);
        dictReq.setPageNum(1);
        PageInfo<DictColumnVO> page = dictColumnService.getPage(dictReq);
        return page == null ? Collections.emptyList() : Optional.ofNullable(page.getList()).orElse(Collections.emptyList());
    }

    @Override
    public Boolean deleteByIds(List<Long> ids) {
        if (CollectionUtils.isEmpty(ids)) {
            return false;
        }

        for (Long id : ids) {
            int usedCount = storeTypeOptionDAO.countByOptionId(id);
            if (usedCount > 0) {
                throw new ServiceException(ErrorCodeEnum.CONFIG_OPTION_USED);
            }
            ConfigOptionDO update = new ConfigOptionDO();
            update.setId(id);
            update.setActive(false);
            configOptionDAO.updateSelective(update);
        }
        return true;
    }
}
