package com.ruoyi.web.modules.category.service.impl;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import com.ruoyi.common.exception.ServiceException;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.web.modules.category.constant.CategoryConstants;
import com.ruoyi.web.modules.category.domain.BizGoodsCategory;
import com.ruoyi.web.modules.category.exception.CategoryBatchDeleteException;
import com.ruoyi.web.modules.category.facade.IGoodsFacade;
import com.ruoyi.web.modules.category.facade.IShopFacade;
import com.ruoyi.web.modules.category.mapper.BizGoodsCategoryMapper;
import com.ruoyi.web.modules.category.service.IPlatformCategoryService;
import com.ruoyi.web.modules.category.service.IShopGoodsCategoryService;
import com.ruoyi.web.modules.category.support.SellerShopContext;
import com.ruoyi.web.modules.category.vo.CategoryLevel2OptionVO;
import com.ruoyi.web.modules.category.vo.CategoryRowVO;
import com.ruoyi.web.modules.category.vo.CategoryScopeVO;
import com.ruoyi.web.modules.category.vo.CategoryTreeResultVO;
import com.ruoyi.web.modules.category.vo.CategoryTreeVO;

/**
 * 商品分类业务实现（平台 shop_id 为 NULL；店铺 shop_id 非空；均最多两级）
 */
@Service
public class CategoryServiceImpl implements IPlatformCategoryService, IShopGoodsCategoryService
{
    @Autowired
    private BizGoodsCategoryMapper categoryMapper;

    @Autowired
    private IGoodsFacade goodsFacade;

    @Autowired
    private IShopFacade shopFacade;

    @Override
    public List<CategoryRowVO> selectPlatformCategoryRowList(String keyword)
    {
        return doSelectCategoryRowList(null, keyword);
    }

    @Override
    public CategoryTreeResultVO selectPlatformCategoryTree(String keyword)
    {
        return doSelectCategoryTree(null, keyword);
    }

    @Override
    public List<BizGoodsCategory> selectPlatformLevel1Options()
    {
        return doSelectLevel1Options(null);
    }

    @Override
    public List<CategoryLevel2OptionVO> selectPlatformLevel2Options()
    {
        return doSelectLevel2Options(null);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public int insertPlatformCategory(BizGoodsCategory category)
    {
        return doInsertCategory(null, category);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public int updatePlatformCategory(BizGoodsCategory category)
    {
        return doUpdateCategory(null, category);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void deletePlatformCategoryByIds(Long[] categoryIds, String operator)
    {
        doDeleteCategoryByIds(null, categoryIds, operator);
    }

    @Override
    public CategoryScopeVO selectScope()
    {
        return doSelectScope(requireShopId());
    }

    @Override
    public List<CategoryRowVO> selectCategoryRowList(String keyword)
    {
        return doSelectCategoryRowList(requireShopId(), keyword);
    }

    @Override
    public CategoryTreeResultVO selectCategoryTree(String keyword)
    {
        return doSelectCategoryTree(requireShopId(), keyword);
    }

    @Override
    public List<BizGoodsCategory> selectLevel1Options()
    {
        return doSelectLevel1Options(requireShopId());
    }

    @Override
    public List<CategoryLevel2OptionVO> selectLevel2Options()
    {
        return doSelectLevel2Options(requireShopId());
    }

    @Override
    public BizGoodsCategory selectCategoryDetail(Long categoryId)
    {
        Long shopId = requireShopId();
        assertScopeMaintable(shopId);
        BizGoodsCategory category = categoryMapper.selectById(categoryId, shopId);
        if (category == null)
        {
            throw new ServiceException("分类不存在");
        }
        return category;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public int insertCategory(BizGoodsCategory category)
    {
        return doInsertCategory(requireShopId(), category);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public int updateCategory(BizGoodsCategory category)
    {
        return doUpdateCategory(requireShopId(), category);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void deleteCategoryByIds(Long[] categoryIds, String operator)
    {
        doDeleteCategoryByIds(requireShopId(), categoryIds, operator);
    }

    private CategoryScopeVO doSelectScope(Long shopId)
    {
        assertScopeMaintable(shopId);
        CategoryScopeVO vo = new CategoryScopeVO();
        vo.setShopId(shopId);
        vo.setShopName(resolveScopeName(shopId));
        return vo;
    }

    private List<CategoryRowVO> doSelectCategoryRowList(Long shopId, String keyword)
    {
        assertScopeMaintable(shopId);
        return buildFlatRows(queryList(shopId, keyword));
    }

    private CategoryTreeResultVO doSelectCategoryTree(Long shopId, String keyword)
    {
        assertScopeMaintable(shopId);
        CategoryTreeResultVO result = new CategoryTreeResultVO();
        result.setShopId(shopId);
        result.setShopName(resolveScopeName(shopId));
        result.setTree(buildTree(queryList(shopId, keyword)));
        return result;
    }

    private List<BizGoodsCategory> doSelectLevel1Options(Long shopId)
    {
        assertScopeMaintable(shopId);
        BizGoodsCategory query = new BizGoodsCategory();
        query.setShopId(shopId);
        query.setCategoryLevel(CategoryConstants.LEVEL_ONE);
        return categoryMapper.selectList(query);
    }

    private List<CategoryLevel2OptionVO> doSelectLevel2Options(Long shopId)
    {
        assertScopeMaintable(shopId);
        BizGoodsCategory query = new BizGoodsCategory();
        query.setShopId(shopId);
        List<BizGoodsCategory> all = categoryMapper.selectList(query);
        Map<Long, String> level1Names = all.stream()
                .filter(c -> CategoryConstants.LEVEL_ONE.equals(c.getCategoryLevel()))
                .collect(Collectors.toMap(BizGoodsCategory::getCategoryId, BizGoodsCategory::getCategoryName, (a, b) -> a));
        List<CategoryLevel2OptionVO> options = new ArrayList<>();
        for (BizGoodsCategory c : all)
        {
            if (!CategoryConstants.LEVEL_TWO.equals(c.getCategoryLevel()))
            {
                continue;
            }
            String parentName = level1Names.getOrDefault(c.getParentId(), "");
            String label = StringUtils.isEmpty(parentName) ? c.getCategoryName() : parentName + " > " + c.getCategoryName();
            options.add(new CategoryLevel2OptionVO(c.getCategoryId(), label, c.getCategoryName()));
        }
        return options;
    }

    private int doInsertCategory(Long shopId, BizGoodsCategory category)
    {
        assertScopeMaintable(shopId);
        validateFields(category);
        normalizeLevelOnSave(category, shopId);
        if (categoryMapper.countByName(shopId, category.getParentId(), category.getCategoryName(), null) > 0)
        {
            throw new ServiceException("同级分类名称已存在");
        }
        category.setShopId(shopId);
        category.setDelFlag(CategoryConstants.DEL_FLAG_NORMAL);
        return categoryMapper.insert(category);
    }

    private int doUpdateCategory(Long shopId, BizGoodsCategory category)
    {
        assertScopeMaintable(shopId);
        if (category.getCategoryId() == null)
        {
            throw new ServiceException("分类ID不能为空");
        }
        BizGoodsCategory existing = categoryMapper.selectById(category.getCategoryId(), shopId);
        if (existing == null)
        {
            throw new ServiceException("分类不存在");
        }
        validateFields(category);
        if (CategoryConstants.LEVEL_ONE.equals(existing.getCategoryLevel()))
        {
            category.setParentId(CategoryConstants.PARENT_ROOT);
            category.setCategoryLevel(CategoryConstants.LEVEL_ONE);
        }
        else
        {
            category.setCategoryLevel(CategoryConstants.LEVEL_TWO);
            validateParentForLevel2(shopId, category.getParentId());
        }
        if (categoryMapper.countByName(shopId, category.getParentId(), category.getCategoryName(),
                category.getCategoryId()) > 0)
        {
            throw new ServiceException("同级分类名称已存在");
        }
        category.setShopId(shopId);
        return categoryMapper.update(category);
    }

    private void doDeleteCategoryByIds(Long shopId, Long[] categoryIds, String operator)
    {
        assertScopeMaintable(shopId);
        if (categoryIds == null || categoryIds.length == 0)
        {
            throw new ServiceException("请选择要删除的分类");
        }
        Set<Long> targetIds = expandDeleteIds(shopId, categoryIds);
        List<String> reasons = new ArrayList<>();
        for (Long id : targetIds)
        {
            BizGoodsCategory cat = categoryMapper.selectById(id, shopId);
            if (cat == null)
            {
                continue;
            }
            if (shopId != null)
            {
                if (goodsFacade.existsByShopCategoryId(id))
                {
                    reasons.add("分类「" + cat.getCategoryName() + "」下存在商品，请先修改商品分类或处理商品");
                }
            }
            else if (goodsFacade.existsByCategoryId(id))
            {
                reasons.add("分类「" + cat.getCategoryName() + "」下存在商品，请先处理商品");
            }
        }
        if (!reasons.isEmpty())
        {
            throw new CategoryBatchDeleteException("部分分类不满足删除条件，整批操作已取消", reasons);
        }
        categoryMapper.logicDeleteByIds(new ArrayList<>(targetIds), shopId, operator);
    }

    private void assertScopeMaintable(Long shopId)
    {
        if (shopId != null)
        {
            shopFacade.assertShopMaintable(shopId);
        }
    }

    private Long requireShopId()
    {
        Long shopId = SellerShopContext.getShopId();
        if (shopId == null || shopId <= 0)
        {
            throw new ServiceException("请先选择当前店铺");
        }
        return shopId;
    }

    private String resolveScopeName(Long shopId)
    {
        if (shopId == null)
        {
            return CategoryConstants.PLATFORM_SCOPE_NAME;
        }
        return shopFacade.getShopName(shopId);
    }

    private List<BizGoodsCategory> queryList(Long shopId, String keyword)
    {
        BizGoodsCategory query = new BizGoodsCategory();
        query.setShopId(shopId);
        query.setKeyword(keyword);
        return categoryMapper.selectList(query);
    }

    private List<CategoryRowVO> buildFlatRows(List<BizGoodsCategory> list)
    {
        List<BizGoodsCategory> ordered = orderCategoriesForFlatList(list);
        List<CategoryRowVO> rows = new ArrayList<>();
        for (BizGoodsCategory c : ordered)
        {
            CategoryRowVO row = new CategoryRowVO();
            row.setCategoryId(c.getCategoryId());
            row.setCategoryName(c.getCategoryName());
            row.setCategoryLevel(c.getCategoryLevel());
            row.setParentId(c.getParentId());
            row.setParentName(c.getParentName());
            row.setCategoryPic(c.getCategoryPic());
            row.setShowFlag(c.getShowFlag());
            row.setHotFlag(c.getHotFlag());
            row.setSortNo(c.getSortNo());
            row.setCanAddChild(CategoryConstants.LEVEL_ONE.equals(c.getCategoryLevel()));
            rows.add(row);
        }
        return rows;
    }

    /**
     * 扁平列表：一级后紧跟其下全部二级（与需求 §5.2 一致）
     */
    private List<BizGoodsCategory> orderCategoriesForFlatList(List<BizGoodsCategory> list)
    {
        if (list == null || list.isEmpty())
        {
            return Collections.emptyList();
        }
        Map<Long, List<BizGoodsCategory>> childrenMap = list.stream()
                .filter(c -> CategoryConstants.LEVEL_TWO.equals(c.getCategoryLevel()))
                .collect(Collectors.groupingBy(BizGoodsCategory::getParentId));
        Comparator<BizGoodsCategory> bySort = Comparator
                .comparing(BizGoodsCategory::getSortNo, Comparator.nullsLast(Integer::compareTo))
                .thenComparing(BizGoodsCategory::getCreateTime, Comparator.nullsLast(Comparator.naturalOrder()))
                .thenComparing(BizGoodsCategory::getCategoryId, Comparator.nullsLast(Long::compareTo));
        List<BizGoodsCategory> ordered = new ArrayList<>();
        Set<Long> included = new LinkedHashSet<>();
        list.stream()
                .filter(c -> CategoryConstants.LEVEL_ONE.equals(c.getCategoryLevel()))
                .sorted(bySort)
                .forEach(l1 -> {
                    ordered.add(l1);
                    included.add(l1.getCategoryId());
                    List<BizGoodsCategory> children = new ArrayList<>(
                            childrenMap.getOrDefault(l1.getCategoryId(), Collections.emptyList()));
                    children.sort(bySort);
                    for (BizGoodsCategory child : children)
                    {
                        ordered.add(child);
                        included.add(child.getCategoryId());
                    }
                });
        list.stream()
                .filter(c -> CategoryConstants.LEVEL_TWO.equals(c.getCategoryLevel()))
                .filter(c -> !included.contains(c.getCategoryId()))
                .sorted(bySort)
                .forEach(ordered::add);
        return ordered;
    }

    private List<CategoryTreeVO> buildTree(List<BizGoodsCategory> list)
    {
        Map<Long, CategoryTreeVO> level1Map = list.stream()
                .filter(c -> CategoryConstants.LEVEL_ONE.equals(c.getCategoryLevel()))
                .collect(Collectors.toMap(BizGoodsCategory::getCategoryId, this::toTreeNode, (a, b) -> a,
                        java.util.LinkedHashMap::new));
        for (BizGoodsCategory c : list)
        {
            if (CategoryConstants.LEVEL_TWO.equals(c.getCategoryLevel()))
            {
                CategoryTreeVO parent = level1Map.get(c.getParentId());
                if (parent != null)
                {
                    parent.getChildren().add(toTreeNode(c));
                }
            }
        }
        return new ArrayList<>(level1Map.values());
    }

    private CategoryTreeVO toTreeNode(BizGoodsCategory c)
    {
        CategoryTreeVO node = new CategoryTreeVO();
        node.setCategoryId(c.getCategoryId());
        node.setCategoryName(c.getCategoryName());
        node.setCategoryLevel(c.getCategoryLevel());
        node.setSortNo(c.getSortNo());
        node.setCategoryPic(c.getCategoryPic());
        node.setShowFlag(c.getShowFlag());
        node.setHotFlag(c.getHotFlag());
        return node;
    }

    private void validateFields(BizGoodsCategory category)
    {
        if (StringUtils.isEmpty(category.getShowFlag()))
        {
            category.setShowFlag(CategoryConstants.SHOW_YES);
        }
        if (StringUtils.isEmpty(category.getHotFlag()))
        {
            category.setHotFlag(CategoryConstants.HOT_NO);
        }
        if (category.getSortNo() == null)
        {
            category.setSortNo(0);
        }
        if (StringUtils.isEmpty(category.getCategoryName()))
        {
            throw new ServiceException("请输入分类名称");
        }
        if (category.getCategoryName().length() > 64)
        {
            throw new ServiceException("分类名称长度不能超过64个字符");
        }
        if (StringUtils.isEmpty(category.getCategoryPic()))
        {
            throw new ServiceException("请上传分类图片");
        }
        if (category.getSortNo() < 0)
        {
            throw new ServiceException("排序须为非负整数");
        }
        validateFlag(category.getShowFlag(), "是否显示");
        validateFlag(category.getHotFlag(), "是否热门");
    }

    private void validateFlag(String flag, String label)
    {
        if (!CategoryConstants.SHOW_YES.equals(flag) && !CategoryConstants.SHOW_NO.equals(flag))
        {
            throw new ServiceException(label + "参数无效");
        }
    }

    private void normalizeLevelOnSave(BizGoodsCategory category, Long shopId)
    {
        if (isLevelTwoCandidate(category))
        {
            validateParentForLevel2(shopId, category.getParentId());
            category.setCategoryLevel(CategoryConstants.LEVEL_TWO);
            return;
        }
        category.setParentId(CategoryConstants.PARENT_ROOT);
        category.setCategoryLevel(CategoryConstants.LEVEL_ONE);
    }

    private boolean isLevelTwoCandidate(BizGoodsCategory category)
    {
        if (CategoryConstants.LEVEL_TWO.equals(category.getCategoryLevel()))
        {
            return true;
        }
        Long parentId = category.getParentId();
        return parentId != null && parentId > 0 && !CategoryConstants.PARENT_ROOT.equals(parentId);
    }

    private void validateParentForLevel2(Long shopId, Long parentId)
    {
        if (parentId == null || CategoryConstants.PARENT_ROOT.equals(parentId))
        {
            throw new ServiceException("二级分类的上级必须是一级分类");
        }
        BizGoodsCategory parent = categoryMapper.selectById(parentId, shopId);
        if (parent == null)
        {
            throw new ServiceException("上级分类不存在");
        }
        if (!CategoryConstants.LEVEL_ONE.equals(parent.getCategoryLevel()))
        {
            throw new ServiceException("不支持三级分类");
        }
    }

    private Set<Long> expandDeleteIds(Long shopId, Long[] categoryIds)
    {
        Set<Long> result = new LinkedHashSet<>();
        for (Long id : categoryIds)
        {
            BizGoodsCategory cat = categoryMapper.selectById(id, shopId);
            if (cat == null)
            {
                throw new ServiceException("分类不存在");
            }
            if (CategoryConstants.LEVEL_ONE.equals(cat.getCategoryLevel()))
            {
                result.addAll(categoryMapper.selectChildIds(shopId, id));
                result.add(id);
            }
            else
            {
                result.add(id);
            }
        }
        return result;
    }
}
