package com.ylx.project.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.ylx.common.core.domain.entity.SysDictData;
import com.ylx.common.exception.ServiceException;
import com.ylx.common.utils.DateUtils;
import com.ylx.common.utils.DictUtils;
import com.ylx.common.utils.SecurityUtils;
import com.ylx.home.hot.domain.vo.ProjectSalesVO;
import com.ylx.home.search.domain.dto.SearchProjectDTO;
import com.ylx.massage.domain.dto.OptionDTO;
import com.ylx.massage.domain.dto.ServiceOptionDTO;
import com.ylx.massage.domain.vo.ProductOptionVO;
import com.ylx.massage.domain.vo.ProductServiceOptionVO;
import com.ylx.massage.service.IMaProjectService;
import com.ylx.merchant.domain.vo.MerchantListVO;
import com.ylx.project.domain.Project;
import com.ylx.project.domain.bookMerchant.dto.BookMerchantDTO;
import com.ylx.project.domain.bookMerchant.vo.BookMerchantVO;
import com.ylx.project.domain.bookMerchant.vo.BookProjectDetailVO;
import com.ylx.project.domain.bookMerchant.vo.ProjectInfoVO;
import com.ylx.project.domain.dto.ProjectAddDTO;
import com.ylx.project.domain.dto.ProjectSearchDTO;
import com.ylx.project.domain.dto.ProjectUpdateDTO;
import com.ylx.project.domain.vo.ProjectBaseVo;
import com.ylx.project.domain.vo.ProjectDetailVo;
import com.ylx.project.domain.vo.ProjectPageVo;
import com.ylx.project.enums.ProjectStatusEnum;
import com.ylx.project.mapper.ProjectMapper;
import com.ylx.project.service.ProjectService;
import com.ylx.servicecategory.domain.ServiceCategory;
import com.ylx.servicecategory.service.ServiceCategoryService;
import com.ylx.system.service.ISysDictDataService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.util.*;
import java.util.stream.Collectors;

import static com.ylx.order.constant.OrderConstant.DICT_UNIT_TYPE;

@Slf4j
@Service
public class ProjectServiceImpl extends ServiceImpl<ProjectMapper, Project> implements ProjectService {

    @Resource
    private ServiceCategoryService serviceCategoryService;
    @Resource
    private ISysDictDataService sysDictDataService;
    @Resource
    private IMaProjectService maProjectService;
    @Resource
    private RedisTemplate<String, String> redisTemplate;

    private static final Map<String, String> unitDictCache = new HashMap<>();

    static {
        List<SysDictData> dictList = DictUtils.getSortedDictCache(DICT_UNIT_TYPE);
        if (CollUtil.isNotEmpty(dictList)) {
            dictList.forEach(dict -> unitDictCache.put(dict.getDictValue(), dict.getDictLabel()));
        } else {
            log.warn("项目计量单位字典未加载，请检查字典配置：{}", DICT_UNIT_TYPE);
        }
    }

    @Override
    public Page<ProjectPageVo> list(Page<Project> page, ProjectSearchDTO dto) {
        LambdaQueryWrapper<Project> queryWrapper = new LambdaQueryWrapper<>();
        // 项目标题
        if (StringUtils.isNotBlank(dto.getTitle())) {
            queryWrapper.like(Project::getTitle, dto.getTitle());
        }
        // 状态
        if (ObjectUtil.isNotEmpty(dto.getStatus())) {
            queryWrapper.eq(Project::getStatus, dto.getStatus());
        }
        // 服务类目ID
        if (ObjectUtil.isNotEmpty(dto.getCategoryId())) {
            queryWrapper.eq(Project::getCategoryId, dto.getCategoryId());
        }
        queryWrapper.orderByDesc(Project::getCreateTime).orderByDesc(Project::getSortOrder);
        Page<ProjectPageVo> pageData = new Page<>();
        pageData.setCurrent(page.getCurrent());
        pageData.setSize(page.getSize());

        Page<Project> projectPage = this.baseMapper.selectPage(page, queryWrapper);
        if (ObjectUtil.isNotNull(projectPage) && CollectionUtil.isNotEmpty(projectPage.getRecords())) {
            List<ProjectPageVo> voList = projectPage.getRecords().stream()
                    .map(this::convertToVo) // 抽取转换方法
                    .collect(Collectors.toList());
            pageData.setRecords(voList);
            pageData.setTotal(projectPage.getTotal());
            pageData.setPages(projectPage.getPages());
        }
        return pageData;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void edit(ProjectUpdateDTO dto) {
        Long id = dto.getId();
        Project entity = this.getById(id);
        if (ObjectUtil.isNull(entity)) {
            throw new IllegalArgumentException("参数有误，项目不存在");
        }

        BeanUtil.copyProperties(dto, entity);
        entity.setUpdateBy(SecurityUtils.getUsername());
        entity.setUpdateTime(DateUtils.getNowDate());

        // 根据项目亮点ID集合获取项目亮点
        String highlightNames = this.buildHighlightNames(dto.getHighlightIds());
        if (StrUtil.isNotEmpty(highlightNames)) {
            entity.setHighlight(highlightNames);
        }

        boolean updateResult = this.updateById(entity);
        if (!updateResult) {
            throw new ServiceException("更新项目失败");
        }

        // ========== 新增：下架时移除热门ZSet ==========
        Integer newStatus = entity.getStatus();
        // 两种场景需要移除：1.本次编辑从上架改为下架；2.本身已是下架（兜底防脏数据）
        if (ObjectUtil.equals(ProjectStatusEnum.OFF_SHELF.getCode(), newStatus)) {
            redisTemplate.opsForZSet().remove("hot:project:rank", String.valueOf(id));
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void add(ProjectAddDTO dto) {

        Project entity = new Project();

        ServiceCategory serviceCategoryDetail = this.serviceCategoryService.getServiceCategoryDetail(dto.getCategoryId());
        if (ObjectUtil.isNull(serviceCategoryDetail)) {
            throw new ServiceException("服务类目不存在");
        }
        BeanUtil.copyProperties(dto, entity);

        entity.setType(serviceCategoryDetail.getServiceTag());
        entity.setCreateBy(SecurityUtils.getUsername());
        entity.setCreateTime(DateUtils.getNowDate());

        // 根据项目亮点ID集合获取项目亮点
        String highlightNames = this.buildHighlightNames(dto.getHighlightIds());
        if (StrUtil.isNotEmpty(highlightNames)) {
            entity.setHighlight(highlightNames);
        }

        boolean saveResult = this.save(entity);
        if (!saveResult) {
            throw new ServiceException("添加项目失败");
        }
    }

    @Override
    public ProjectDetailVo getDetailsInfo(Long id) {
        if (ObjectUtil.isNull(id)) {
            throw new ServiceException("项目ID不能为空");
        }
        ProjectDetailVo detailVo = this.baseMapper.selectProjectDetailById(id);
        if (ObjectUtil.isNull(detailVo)) {
            throw new ServiceException("项目不存在");
        }
        return detailVo;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void deleteProjectById(Long id) {
        if (ObjectUtil.isNull(id)) {
            throw new ServiceException("项目ID不能为空");
        }
        if (id <= 0) {
            throw new ServiceException("项目ID不正确");
        }
        log.info("根据主键ID删除项目，ID：{}", id);
        int deleteResult = this.baseMapper.deleteProjectById(id);
        if (deleteResult <= 0) {
            throw new ServiceException("项目不存在或已删除");
        }
    }

    @Override
    public IPage<ProductOptionVO> selectOptionUnionPage(Page page, OptionDTO dto) {
        return baseMapper.selectOptionUnionPage(page, dto);
    }

    @Override
    public Page<ProductServiceOptionVO> selectServiceOptionsPage(Page page, ServiceOptionDTO dto) {
        return baseMapper.selectServiceOptionsPage(page, dto);
    }

    @Override
    public List<ProjectBaseVo> getProjectTabListByCategoryId(Integer categoryId) {

        LambdaQueryWrapper<Project> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(Project::getCategoryId, categoryId)
                .eq(Project::getStatus, ProjectStatusEnum.ON_SHELF.getCode());

        List<Project> projects = this.baseMapper.selectList(wrapper);

        return BeanUtil.copyToList(projects, ProjectBaseVo.class);
    }

    @Override
    public BookProjectDetailVO getBookingProjectDetail(BookMerchantDTO dto) {
        BookProjectDetailVO vo = new BookProjectDetailVO();

        Long projectId = dto.getProjectId();

        // 1. 查询项目基础信息
        Project project = this.baseMapper.selectById(projectId);
        if (ObjectUtil.isNull(project)) {
            throw new ServiceException("项目不存在");
        }

        if (ObjectUtil.equals(project.getStatus(), ProjectStatusEnum.OFF_SHELF.getCode())) {
            throw new ServiceException("项目已下架");
        }

        ProjectInfoVO projectInfo = new ProjectInfoVO();
        BeanUtil.copyProperties(project, projectInfo);
        vo.setProjectInfo(projectInfo);

        // 2. 查询商户列表
        Page<BookMerchantVO> page = maProjectService.selectMerchantList(new Page<>(dto.getCurrent(), dto.getSize()), dto);

        // 3.判断数据中的currentPrice为null就设置为projectInfo的price
        if (ObjectUtil.isNotNull(page) && CollUtil.isNotEmpty(page.getRecords())) {
            for (BookMerchantVO merchantVO : page.getRecords()) {
                BigDecimal price = merchantVO.getCurrentPrice();
                // 为空 或者 等于0，统一赋值项目原价
                if (ObjectUtil.isNull(price) || price.compareTo(BigDecimal.ZERO) == 0) {
                    merchantVO.setCurrentPrice(projectInfo.getPrice());
                }
            }
        }
        vo.setMerchantList(page);
        return vo;
    }

    @Override
    public List<ProjectBaseVo> listProjects() {
        LambdaQueryWrapper<Project> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(Project::getStatus, ProjectStatusEnum.ON_SHELF.getCode());

        List<Project> projects = this.baseMapper.selectList(wrapper);

        return BeanUtil.copyToList(projects, ProjectBaseVo.class);
    }

    @Override
    public List<Project> selectProjectPage(long offset, long fetchCount) {
        return this.baseMapper.selectProjectPage(offset, fetchCount);
    }

    @Override
    public Long countValidProject() {
        return this.baseMapper.countValidProject();
    }

    @Override
    public void batchUpdateSales(List<ProjectSalesVO> batch) {
        this.baseMapper.batchUpdateSales(batch);
    }

    @Override
    public List<ProjectSalesVO> selectAllProjectSalesCount() {
        return this.baseMapper.selectAllProjectSalesCount();
    }

    @Override
    public Page<ProjectInfoVO> homeSearchPage(SearchProjectDTO dto) {
        Page<ProjectInfoVO> page = new Page<>(dto.getCurrent(), dto.getSize());
        page = this.baseMapper.getProjectPage(page, dto);
        List<ProjectInfoVO> records = page.getRecords();
        if (CollUtil.isNotEmpty(records)) {
            for (ProjectInfoVO record : records) {
                Integer unitType = record.getUnitType();
                String unitKey = ObjectUtil.isNotNull(unitType) ? unitType.toString() : "";
                String unitTypeName = unitDictCache.getOrDefault(unitKey, "未知单位");
                record.setUnitTypeName(unitTypeName);
            }
        }
        return page;
    }

    private ProjectPageVo convertToVo(Project entity) {
        ProjectPageVo vo = new ProjectPageVo();
        // 属性拷贝（推荐）
        BeanUtil.copyProperties(entity, vo);
        return vo;
    }


    /**
     * 根据亮点ID集合构建高亮名称字符串
     *
     * @param highlightIds 逗号分隔的ID字符串或单个ID
     * @return 拼接好的名称字符串，如 "技术领先,市场广阔"
     */
    private String buildHighlightNames(String highlightIds) {
        // 1. 基础校验：如果ID为空，直接返回空字符串，避免后续查库
        if (StringUtils.isBlank(highlightIds)) {
            return "";
        }

        // 2. 解析ID列表 (兼容逗号分隔的情况)
        List<String> idList = Arrays.asList(highlightIds.split(","));

        // 3. 批量查询字典表
        List<SysDictData> dictList = this.sysDictDataService.list(
                new QueryWrapper<SysDictData>()
                        .in("dict_code", idList)
                        .select("dict_label") // 【性能优化】只查询需要的字段，减少IO开销
        );

        // 4. 提取名称并拼接
        return dictList.stream()
                .map(SysDictData::getDictLabel)
                .filter(StringUtils::isNotBlank) // 过滤掉可能为空的标签
                .collect(Collectors.joining(","));
    }

}
