package com.hotwj.platform.securityManagement.trainingOutline.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.hotwj.platform.resourceManagement.company.service.ISysUserLoginPortService;
import com.hotwj.platform.securityManagement.trainingOutline.domain.HotTrainingOutline;
import com.hotwj.platform.securityManagement.trainingOutline.domain.bo.HotTrainingOutlineBo;
import com.hotwj.platform.securityManagement.trainingOutline.domain.vo.HotTrainingOutlineVo;
import com.hotwj.platform.securityManagement.trainingOutline.mapper.HotTrainingOutlineMapper;
import com.hotwj.platform.securityManagement.trainingOutline.service.IHotTrainingOutlineService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.dromara.common.core.domain.model.LoginUser;
import org.dromara.common.core.exception.ServiceException;
import org.dromara.common.core.service.DictService;
import org.dromara.common.core.utils.MapstructUtils;
import org.dromara.common.core.utils.StringUtils;
import org.dromara.common.mybatis.core.page.PageQuery;
import org.dromara.common.mybatis.core.page.TableDataInfo;
import org.dromara.common.satoken.utils.LoginHelper;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.stream.Collectors;

/**
 * 培训大纲Service业务层处理
 *
 * @author shihongwei
 * @date 2026-05-14
 */
@Slf4j
@RequiredArgsConstructor
@Service
public class HotTrainingOutlineServiceImpl implements IHotTrainingOutlineService {

    private static final long LEVEL_ANNUAL = 1L;
    private static final long LEVEL_MONTHLY = 2L;
    private static final long LEVEL_WEEKLY = 3L;

    private final HotTrainingOutlineMapper baseMapper;
    private final DictService dictService;

    @Override
    public HotTrainingOutlineVo queryById(Long id) {
        HotTrainingOutlineVo vo = baseMapper.selectVoById(id);
        if (vo == null) {
            return null;
        }
        if (shouldFilterDisabledForCurrentUser() && !Long.valueOf(1L).equals(vo.getIsEnabled())) {
            return null;
        }
        fillExtraFields(List.of(vo));
        return vo;
    }

    @Override
    public TableDataInfo<HotTrainingOutlineVo> queryPageList(HotTrainingOutlineBo bo, PageQuery pageQuery) {
        LambdaQueryWrapper<HotTrainingOutline> lqw = buildQueryWrapper(bo);
        Page<HotTrainingOutlineVo> result = baseMapper.selectVoPage(pageQuery.build(), lqw);
        List<HotTrainingOutlineVo> records = result.getRecords();
        if (records != null && !records.isEmpty()) {
            fillExtraFields(records);
        }
        return TableDataInfo.build(result);
    }

    @Override
    public List<HotTrainingOutlineVo> queryList(HotTrainingOutlineBo bo) {
        List<HotTrainingOutlineVo> list = baseMapper.selectVoList(buildQueryWrapper(bo));
        fillExtraFields(list);
        return list;
    }

    @Override
    public List<HotTrainingOutlineVo> queryAnnualList(HotTrainingOutlineBo bo) {
        HotTrainingOutlineBo queryBo = bo == null ? new HotTrainingOutlineBo() : bo;
        queryBo.setOutlineLevel(LEVEL_ANNUAL);
        queryBo.setParentId(0L);
        List<HotTrainingOutlineVo> list = baseMapper.selectVoList(buildQueryWrapper(queryBo));
        fillExtraFields(list);
        return list;
    }

    @Override
    public List<HotTrainingOutlineVo> queryChildrenByParentId(Long parentId) {
        HotTrainingOutline parent = baseMapper.selectById(parentId);
        if (parent == null || Long.valueOf(1L).equals(parent.getIsDeleted())) {
            throw new ServiceException("父级培训大纲不存在");
        }
        List<HotTrainingOutlineVo> children = baseMapper.selectVoList(
            Wrappers.<HotTrainingOutline>lambdaQuery()
                .eq(HotTrainingOutline::getParentId, parentId)
                .eq(shouldFilterDisabledForCurrentUser(), HotTrainingOutline::getIsEnabled, 1L)
                .eq(HotTrainingOutline::getIsDeleted, 0L)
                .orderByAsc(HotTrainingOutline::getSortNo)
                .orderByAsc(HotTrainingOutline::getId)
        );
        fillExtraFields(children);
        return children;
    }

    private LambdaQueryWrapper<HotTrainingOutline> buildQueryWrapper(HotTrainingOutlineBo bo) {
        LambdaQueryWrapper<HotTrainingOutline> lqw = Wrappers.lambdaQuery();
        lqw.eq(bo.getId() != null, HotTrainingOutline::getId, bo.getId());
        lqw.eq(bo.getCompanyId() != null, HotTrainingOutline::getCompanyId, bo.getCompanyId());
        lqw.eq(bo.getParentId() != null, HotTrainingOutline::getParentId, bo.getParentId());
        lqw.eq(bo.getOutlineLevel() != null, HotTrainingOutline::getOutlineLevel, bo.getOutlineLevel());
        lqw.like(StringUtils.isNotBlank(bo.getOutlineName()), HotTrainingOutline::getOutlineName, bo.getOutlineName());
        lqw.eq(StringUtils.isNotBlank(bo.getTrainingType()), HotTrainingOutline::getTrainingType, bo.getTrainingType());
        lqw.eq(bo.getIsEnabled() != null, HotTrainingOutline::getIsEnabled, bo.getIsEnabled());
        lqw.eq(bo.getIsDeleted() != null, HotTrainingOutline::getIsDeleted, bo.getIsDeleted());
        if (shouldFilterDisabledForCurrentUser()) {
            lqw.eq(HotTrainingOutline::getIsEnabled, 1L);
        }
        lqw.orderByAsc(HotTrainingOutline::getSortNo)
            .orderByAsc(HotTrainingOutline::getId);
        return lqw;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean insertByBo(HotTrainingOutlineBo bo) {
        HotTrainingOutline add = MapstructUtils.convert(bo, HotTrainingOutline.class);
        prepareEntity(add, null);
        validEntityBeforeSave(add);
        boolean flag = baseMapper.insert(add) > 0;
        if (flag) {
            bo.setId(add.getId());
        }
        return flag;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean updateByBo(HotTrainingOutlineBo bo) {
        HotTrainingOutline current = baseMapper.selectById(bo.getId());
        if (current == null || Long.valueOf(1L).equals(current.getIsDeleted())) {
            throw new ServiceException("培训大纲不存在");
        }
        HotTrainingOutline update = MapstructUtils.convert(bo, HotTrainingOutline.class);
        prepareEntity(update, current);
        validEntityBeforeSave(update);
        return baseMapper.updateById(update) > 0;
    }

    private void prepareEntity(HotTrainingOutline entity, HotTrainingOutline current) {
        if (entity.getCompanyId() == null) {
            entity.setCompanyId(current != null ? current.getCompanyId() : resolveCurrentCompanyId());
        }
        if (entity.getSortNo() == null) {
            entity.setSortNo(current != null && current.getSortNo() != null ? current.getSortNo() : 0L);
        }
        if (!canManageEnabled()) {
            entity.setIsEnabled(current != null && current.getIsEnabled() != null ? current.getIsEnabled() : 1L);
        } else if (entity.getIsEnabled() == null) {
            entity.setIsEnabled(current != null && current.getIsEnabled() != null ? current.getIsEnabled() : 1L);
        }
        if (entity.getIsDeleted() == null) {
            entity.setIsDeleted(current != null && current.getIsDeleted() != null ? current.getIsDeleted() : 0L);
        }
        if (Objects.equals(entity.getOutlineLevel(), LEVEL_ANNUAL)) {
            entity.setParentId(0L);
        } else if (entity.getParentId() == null && current != null) {
            entity.setParentId(current.getParentId());
        }
    }

    private void validEntityBeforeSave(HotTrainingOutline entity) {
        if (!isSupportedLevel(entity.getOutlineLevel())) {
            throw new ServiceException("大纲层级仅支持年度、月度、周度");
        }
        if (StringUtils.isBlank(entity.getOutlineName())) {
            throw new ServiceException("大纲名称不能为空");
        }
        if (StringUtils.isBlank(entity.getOutlineFile())) {
            throw new ServiceException("大纲文件不能为空");
        }
        if (StringUtils.isBlank(entity.getTrainingType())) {
            throw new ServiceException("培训类型不能为空");
        }
        if (entity.getIsEnabled() != null && !Objects.equals(entity.getIsEnabled(), 0L) && !Objects.equals(entity.getIsEnabled(), 1L)) {
            throw new ServiceException("是否启用取值仅支持0和1");
        }

        if (Objects.equals(entity.getOutlineLevel(), LEVEL_MONTHLY)) {
            HotTrainingOutline parent = requireParent(entity.getParentId(), "月度大纲");
            if (!Objects.equals(parent.getOutlineLevel(), LEVEL_ANNUAL)) {
                throw new ServiceException("月度大纲的上级必须是年度大纲");
            }
            inheritCompanyFromParent(entity, parent);
        } else if (Objects.equals(entity.getOutlineLevel(), LEVEL_WEEKLY)) {
            HotTrainingOutline parent = requireParent(entity.getParentId(), "周度大纲");
            if (!Objects.equals(parent.getOutlineLevel(), LEVEL_MONTHLY)) {
                throw new ServiceException("周度大纲的上级必须是月度大纲");
            }
            inheritCompanyFromParent(entity, parent);
        }

        LambdaQueryWrapper<HotTrainingOutline> duplicateWrapper = Wrappers.lambdaQuery();
        duplicateWrapper.eq(HotTrainingOutline::getOutlineLevel, entity.getOutlineLevel())
            .eq(HotTrainingOutline::getParentId, entity.getParentId())
            .eq(HotTrainingOutline::getOutlineName, entity.getOutlineName())
            .eq(HotTrainingOutline::getIsDeleted, 0L)
            .ne(entity.getId() != null, HotTrainingOutline::getId, entity.getId());
        if (entity.getCompanyId() != null) {
            duplicateWrapper.eq(HotTrainingOutline::getCompanyId, entity.getCompanyId());
        }
        if (baseMapper.selectCount(duplicateWrapper) > 0) {
            throw new ServiceException("同级下已存在同名培训大纲");
        }
    }

    private HotTrainingOutline requireParent(Long parentId, String currentLevelName) {
        if (parentId == null || parentId <= 0) {
            throw new ServiceException(currentLevelName + "必须选择上级大纲");
        }
        HotTrainingOutline parent = baseMapper.selectById(parentId);
        if (parent == null || Long.valueOf(1L).equals(parent.getIsDeleted())) {
            throw new ServiceException("上级培训大纲不存在");
        }
        if (shouldFilterDisabledForCurrentUser() && !Long.valueOf(1L).equals(parent.getIsEnabled())) {
            throw new ServiceException("上级培训大纲不存在");
        }
        return parent;
    }

    private void inheritCompanyFromParent(HotTrainingOutline entity, HotTrainingOutline parent) {
        if (entity.getCompanyId() == null) {
            entity.setCompanyId(parent.getCompanyId());
        }
        if (entity.getCompanyId() != null && parent.getCompanyId() != null
            && !Objects.equals(entity.getCompanyId(), parent.getCompanyId())) {
            throw new ServiceException("子级大纲与上级大纲的公司归属必须一致");
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid) {
        if (ids == null || ids.isEmpty()) {
            return false;
        }
        if (isValid) {
            Long childCount = baseMapper.selectCount(
                Wrappers.<HotTrainingOutline>lambdaQuery()
                    .in(HotTrainingOutline::getParentId, ids)
                    .eq(HotTrainingOutline::getIsDeleted, 0L)
            );
            if (childCount != null && childCount > 0) {
                throw new ServiceException("存在下级培训大纲，无法删除");
            }
        }
        return baseMapper.deleteByIds(ids) > 0;
    }

    private void fillExtraFields(List<HotTrainingOutlineVo> list) {
        if (list == null || list.isEmpty()) {
            return;
        }
        Set<Long> parentIds = list.stream()
            .map(HotTrainingOutlineVo::getParentId)
            .filter(Objects::nonNull)
            .filter(parentId -> parentId > 0)
            .collect(Collectors.toCollection(LinkedHashSet::new));
        Map<Long, String> parentNameMap = new HashMap<>();
        if (!parentIds.isEmpty()) {
            parentNameMap = baseMapper.selectBatchIds(parentIds).stream()
                .filter(Objects::nonNull)
                .collect(Collectors.toMap(HotTrainingOutline::getId, HotTrainingOutline::getOutlineName, (a, b) -> a));
        }

        Set<Long> currentIds = list.stream()
            .map(HotTrainingOutlineVo::getId)
            .filter(Objects::nonNull)
            .collect(Collectors.toCollection(LinkedHashSet::new));
        Map<Long, Long> childCountMap = Collections.emptyMap();
        if (!currentIds.isEmpty()) {
            childCountMap = baseMapper.selectList(
                Wrappers.<HotTrainingOutline>lambdaQuery()
                    .select(HotTrainingOutline::getId, HotTrainingOutline::getParentId)
                    .in(HotTrainingOutline::getParentId, currentIds)
                    .eq(HotTrainingOutline::getIsDeleted, 0L)
            ).stream().collect(Collectors.groupingBy(HotTrainingOutline::getParentId, Collectors.counting()));
        }

        for (HotTrainingOutlineVo vo : list) {
            vo.setParentName(parentNameMap.get(vo.getParentId()));
            vo.setOutlineLevelName(resolveLevelName(vo.getOutlineLevel()));
            if (StringUtils.isNotBlank(vo.getTrainingType())) {
                String label = dictService.getDictLabel("hot_training_type", vo.getTrainingType());
                vo.setTrainingTypeLabel(StringUtils.isNotBlank(label) ? label : vo.getTrainingType());
            }
            vo.setHasChildren(childCountMap.getOrDefault(vo.getId(), 0L) > 0);
        }
    }

    private String resolveLevelName(Long outlineLevel) {
        if (Objects.equals(outlineLevel, LEVEL_ANNUAL)) {
            return "年度";
        }
        if (Objects.equals(outlineLevel, LEVEL_MONTHLY)) {
            return "月度";
        }
        if (Objects.equals(outlineLevel, LEVEL_WEEKLY)) {
            return "周度";
        }
        return "";
    }

    private boolean isSupportedLevel(Long outlineLevel) {
        return Objects.equals(outlineLevel, LEVEL_ANNUAL)
            || Objects.equals(outlineLevel, LEVEL_MONTHLY)
            || Objects.equals(outlineLevel, LEVEL_WEEKLY);
    }

    private Long resolveCurrentCompanyId() {
        try {
            return LoginHelper.getCompanyId();
        } catch (Exception e) {
            log.debug("resolveCurrentCompanyId failed", e);
            return null;
        }
    }

    private boolean shouldFilterDisabledForCurrentUser() {
        if (LoginHelper.isSuperAdmin() || LoginHelper.isTenantAdmin()) {
            return false;
        }
        LoginUser loginUser = LoginHelper.getLoginUser();
        return loginUser != null && ISysUserLoginPortService.ENTERPRISE_PORT.equals(loginUser.getLoginPort());
    }

    private boolean canManageEnabled() {
        if (LoginHelper.isSuperAdmin() || LoginHelper.isTenantAdmin()) {
            return true;
        }
        LoginUser loginUser = LoginHelper.getLoginUser();
        return loginUser != null && ISysUserLoginPortService.HEADQUARTERS_PORT.equals(loginUser.getLoginPort());
    }
}
