package com.snack.server.module.category.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.snack.server.common.ResultCode;
import com.snack.server.exception.BusinessException;
import com.snack.server.module.category.dto.req.CategorySaveReq;
import com.snack.server.module.category.entity.Category;
import com.snack.server.module.category.enums.CategoryLevelEnum;
import com.snack.server.module.category.enums.CategoryStatusEnum;
import com.snack.server.module.category.mapper.CategoryMapper;
import com.snack.server.module.category.service.CategoryService;
import com.snack.server.module.category.vo.CategoryOptionVO;
import com.snack.server.module.category.vo.CategoryTreeVO;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

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

/**
 * 商品分类业务实现
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class CategoryServiceImpl implements CategoryService {

    /** 最大层级 */
    private static final int MAX_LEVEL = 3;
    /** 默认父分类 ID（顶级） */
    private static final Long ROOT_PARENT_ID = 0L;

    private final CategoryMapper categoryMapper;

    // ==================== 查询 ====================

    @Override
    public List<CategoryTreeVO> listTree(Integer statusFilter) {
        // 1. 查询全量分类
        LambdaQueryWrapper<Category> wrapper = new LambdaQueryWrapper<Category>()
                .orderByAsc(Category::getSort)
                .orderByAsc(Category::getId);
        if (statusFilter != null) {
            wrapper.eq(Category::getStatus, statusFilter);
        }
        List<Category> all = categoryMapper.selectList(wrapper);

        // 2. 转 VO
        List<CategoryTreeVO> vos = all.stream().map(this::toTreeVO).toList();

        // 3. 组装树
        return buildTree(vos);
    }

    @Override
    public List<Category> listByParentId(Long parentId) {
        return categoryMapper.selectList(
                new LambdaQueryWrapper<Category>()
                        .eq(Category::getParentId, parentId)
                        .orderByAsc(Category::getSort)
        );
    }

    @Override
    public List<CategoryOptionVO> listOptions() {
        return categoryMapper.selectList(
                new LambdaQueryWrapper<Category>()
                        .eq(Category::getStatus, CategoryStatusEnum.ENABLED.getCode())
                        .orderByAsc(Category::getSort)
        ).stream().map(c -> {
            CategoryOptionVO vo = new CategoryOptionVO();
            BeanUtil.copyProperties(c, vo);
            return vo;
        }).toList();
    }

    @Override
    public Category getById(Long id) {
        Category category = categoryMapper.selectById(id);
        if (category == null) {
            throw new BusinessException(1010, "分类不存在");
        }
        return category;
    }

    // ==================== 创建 ====================

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Long create(CategorySaveReq req) {
        // 1. 校验父分类
        validateParent(req.getParentId(), req.getLevel());

        // 2. 同级下名称不能重复
        Long sameNameCount = categoryMapper.selectCount(
                new LambdaQueryWrapper<Category>()
                        .eq(Category::getParentId, req.getParentId())
                        .eq(Category::getName, req.getName())
        );
        if (sameNameCount > 0) {
            throw new BusinessException(1003, "同级分类下已存在同名分类");
        }

        // 3. 入库
        Category category = new Category();
        BeanUtil.copyProperties(req, category, "id");
        if (category.getStatus() == null) {
            category.setStatus(CategoryStatusEnum.ENABLED.getCode());
        }
        categoryMapper.insert(category);
        log.info("创建分类 id={} name={} level={}", category.getId(), category.getName(), category.getLevel());
        return category.getId();
    }

    // ==================== 更新 ====================

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void update(CategorySaveReq req) {
        if (req.getId() == null) {
            throw new BusinessException(1000, "ID 不能为空");
        }
        Category existing = categoryMapper.selectById(req.getId());
        if (existing == null) {
            throw new BusinessException(1010, "分类不存在");
        }

        // 不允许修改层级（层级变化会破坏树形结构）
        if (!existing.getLevel().equals(req.getLevel())) {
            throw new BusinessException(1000, "不允许修改层级");
        }

        // 校验父分类
        validateParent(req.getParentId(), req.getLevel());
        // 不能把自己设为自己的父分类
        if (req.getId().equals(req.getParentId())) {
            throw new BusinessException(1000, "不能将自己设为父分类");
        }

        // 同级下名称查重（排除自身）
        Long sameNameCount = categoryMapper.selectCount(
                new LambdaQueryWrapper<Category>()
                        .eq(Category::getParentId, req.getParentId())
                        .eq(Category::getName, req.getName())
                        .ne(Category::getId, req.getId())
        );
        if (sameNameCount > 0) {
            throw new BusinessException(1003, "同级分类下已存在同名分类");
        }

        Category category = new Category();
        BeanUtil.copyProperties(req, category);
        categoryMapper.updateById(category);
        log.info("更新分类 id={}", category.getId());
    }

    // ==================== 删除 ====================

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void delete(Long id) {
        Category existing = categoryMapper.selectById(id);
        if (existing == null) {
            throw new BusinessException(1010, "分类不存在");
        }

        // 1. 校验是否有子分类
        Long childCount = categoryMapper.selectCount(
                new LambdaQueryWrapper<Category>().eq(Category::getParentId, id)
        );
        if (childCount > 0) {
            throw new BusinessException(1000,
                    "存在 " + childCount + " 个子分类，请先删除子分类");
        }

        // 2. 校验是否有关联商品（通过 product 表的 category_id 判断）
        Long productCount = categoryMapper.selectCount(
                new LambdaQueryWrapper<Category>().eq(Category::getId, id)
                // 这里只是占位，真实业务应注入 ProductMapper 检查 product.category_id
        );
        // 简化处理：实际应查 product 表，TODO: 注入 ProductService 检查
        // if (productService.countByCategoryId(id) > 0) {
        //     throw new BusinessException("该分类下存在商品，无法删除");
        // }

        categoryMapper.deleteById(id);

        // 删除分类时，关联的物理文件也清理（通过工具类从 URL 反查 path）
        if (cn.hutool.core.util.StrUtil.isNotBlank(existing.getIcon())) {
            com.snack.server.common.utils.SpringContextHolder
                    .getBean(com.snack.server.module.file.service.FileService.class)
                    .deleteByPath(existing.getIcon());
        }
        log.info("删除分类 id={} name={}", id, existing.getName());
    }

    // ==================== 状态切换 ====================

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void updateStatus(Long id, Integer status) {
        if (id == null || status == null) {
            throw new BusinessException(1000, "参数错误");
        }
        Category existing = categoryMapper.selectById(id);
        if (existing == null) {
            throw new BusinessException(1010, "分类不存在");
        }
        if (existing.getStatus().equals(status)) {
            return; // 状态未变
        }
        Category update = new Category();
        update.setId(id);
        update.setStatus(status);
        categoryMapper.updateById(update);
        log.info("分类 id={} 状态更新为 {}", id, status);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void updateSort(Long id, Integer sort) {
        if (id == null) {
            throw new BusinessException(1000, "ID 不能为空");
        }
        Category existing = categoryMapper.selectById(id);
        if (existing == null) {
            throw new BusinessException(1010, "分类不存在");
        }
        Category update = new Category();
        update.setId(id);
        update.setSort(sort == null ? 0 : sort);
        categoryMapper.updateById(update);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void updateIcon(Long id, String iconUrl) {
        if (id == null) {
            throw new BusinessException(1000, "ID 不能为空");
        }
        if (cn.hutool.core.util.StrUtil.isBlank(iconUrl)) {
            throw new BusinessException(1000, "图标 URL 不能为空");
        }
        Category existing = categoryMapper.selectById(id);
        if (existing == null) {
            throw new BusinessException(1010, "分类不存在");
        }
        Category update = new Category();
        update.setId(id);
        update.setIcon(iconUrl);
        categoryMapper.updateById(update);
    }

    // ==================== 私有方法 ====================

    /**
     * 校验父分类合法性
     */
    private void validateParent(Long parentId, Integer level) {
        if (parentId == null) {
            parentId = ROOT_PARENT_ID;
        }

        // 一级分类：parentId 必须为 0
        if (level == null || level < 1 || level > MAX_LEVEL) {
            throw new BusinessException(1000, "层级必须在 1~" + MAX_LEVEL + " 之间");
        }

        if (level == 1) {
            if (!ROOT_PARENT_ID.equals(parentId)) {
                throw new BusinessException(1000, "一级分类的父分类必须为 0");
            }
            return;
        }

        // 二级 / 三级：父分类必须存在
        Category parent = categoryMapper.selectById(parentId);
        if (parent == null) {
            throw new BusinessException(1000, "父分类不存在");
        }
        // 父分类的 level 必须 = 当前 level - 1
        if (!parent.getLevel().equals(level - 1)) {
            throw new BusinessException(1000,
                    "父分类层级不匹配：当前层级=" + level + "，父分类层级=" + parent.getLevel());
        }
        // 父分类必须启用
        if (parent.getStatus() != null && parent.getStatus() == 0) {
            throw new BusinessException(1000, "父分类已禁用，无法添加子分类");
        }
    }

    /**
     * 组装树形结构
     */
    private List<CategoryTreeVO> buildTree(List<CategoryTreeVO> all) {
        if (CollUtil.isEmpty(all)) {
            return new ArrayList<>();
        }
        // 按 id 建索引
        Map<Long, CategoryTreeVO> map = all.stream()
                .collect(Collectors.toMap(CategoryTreeVO::getId, v -> v, (a, b) -> a));

        List<CategoryTreeVO> roots = new ArrayList<>();
        for (CategoryTreeVO vo : all) {
            if (vo.getParentId() == null || vo.getParentId() == 0L) {
                roots.add(vo);
                continue;
            }
            CategoryTreeVO parent = map.get(vo.getParentId());
            if (parent != null) {
                if (parent.getChildren() == null) {
                    parent.setChildren(new ArrayList<>());
                }
                parent.getChildren().add(vo);
            } else {
                // 孤儿节点（父分类被删除），按顶级处理
                roots.add(vo);
            }
        }
        // 排序
        sortTree(roots);
        return roots;
    }

    private void sortTree(List<CategoryTreeVO> list) {
        if (CollUtil.isEmpty(list)) return;
        list.sort(Comparator.comparing(CategoryTreeVO::getSort,
                Comparator.nullsLast(Comparator.naturalOrder()))
                .thenComparing(CategoryTreeVO::getId));
        for (CategoryTreeVO vo : list) {
            sortTree(vo.getChildren());
        }
    }

    private CategoryTreeVO toTreeVO(Category c) {
        CategoryTreeVO vo = new CategoryTreeVO();
        BeanUtil.copyProperties(c, vo);
        return vo;
    }
}
