package com.usky.ems.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.usky.common.mybatis.core.AbstractCrudService;
import com.usky.common.security.utils.SecurityUtils;
import com.usky.ems.domain.BaseSpace;
import com.usky.ems.mapper.BaseSpaceMapper;
import com.usky.ems.service.BaseSpaceService;
import com.usky.ems.service.vo.BaseSpaceForestNodeVO;
import org.springframework.stereotype.Service;

import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
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;

/**
 * 空间服务实现（base_space）
 */
@Service
public class BaseSpaceServiceImpl extends AbstractCrudService<BaseSpaceMapper, BaseSpace> implements BaseSpaceService {

    @Override
    public BaseSpaceForestNodeVO tree() {
        List<BaseSpace> allSpaces = this.list();
        if (allSpaces == null || allSpaces.isEmpty()) {
            return null;
        }

        List<BaseSpaceForestNodeVO> allNodes = allSpaces.stream()
                .map(this::toNode)
                .collect(Collectors.toList());

        allNodes.sort(Comparator.comparing(
                BaseSpaceForestNodeVO::getName,
                Comparator.nullsFirst(String::compareToIgnoreCase)
        ));

        Map<Long, BaseSpaceForestNodeVO> idNodeMap = new HashMap<>();
        for (BaseSpaceForestNodeVO node : allNodes) {
            if (node.getId() != null) {
                idNodeMap.put(node.getId(), node);
            }
        }

        List<BaseSpaceForestNodeVO> roots = new ArrayList<>();
        for (BaseSpaceForestNodeVO node : allNodes) {
            Long parentId = node.getParentId();
            if (parentId != null && parentId != 0L) {
                BaseSpaceForestNodeVO parent = idNodeMap.get(parentId);
                if (parent != null) {
                    node.setParentSpaceName(parent.getName());
                    parent.getChildren().add(node);
                } else {
                    roots.add(node);
                }
            } else {
                roots.add(node);
            }
        }

        if (roots.isEmpty()) {
            return null;
        }

        List<BaseSpaceForestNodeVO> distinctRoots = roots.stream()
                .filter(Objects::nonNull)
                .distinct()
                .collect(Collectors.toList());

        if (distinctRoots.size() == 1) {
            return distinctRoots.get(0);
        }

        BaseSpaceForestNodeVO virtualRoot = new BaseSpaceForestNodeVO();
        virtualRoot.setId(0L);
        virtualRoot.setName("ROOT");
        virtualRoot.setChildren(distinctRoots);
        return virtualRoot;
    }

    @Override
    public List<Long> getAuthorizedSpaceIds(Long spaceId) {
        if (spaceId == null) {
            return Collections.emptyList();
        }
        Set<Long> ids = new LinkedHashSet<>();
        ids.add(spaceId);
        for (BaseSpace child : recursiveAllChildrenNode(spaceId)) {
            if (child != null && child.getId() != null) {
                ids.add(child.getId());
            }
        }
        return new ArrayList<>(ids);
    }

    @Override
    public List<BaseSpace> recursiveAllChildrenNode(Long spaceId) {
        if (spaceId == null) {
            return Collections.emptyList();
        }
        List<BaseSpace> result = new ArrayList<>();
        collectChildren(spaceId, result);
        return result;
    }

    private void collectChildren(Long parentId, List<BaseSpace> out) {
        List<BaseSpace> children = this.list(new com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper<BaseSpace>()
                .eq(BaseSpace::getParentId, parentId));
        if (children == null || children.isEmpty()) {
            return;
        }
        out.addAll(children);
        for (BaseSpace child : children) {
            if (child != null && child.getId() != null) {
                collectChildren(child.getId(), out);
            }
        }
    }

    private BaseSpaceForestNodeVO toNode(BaseSpace space) {
        BaseSpaceForestNodeVO vo = new BaseSpaceForestNodeVO();
        vo.setId(space.getId());
        vo.setName(space.getName());
        vo.setParentId(space.getParentId());
        vo.setType(space.getType());
        vo.setRootId(space.getRootId());
        vo.setPath(space.getPath());
        vo.setDeep(space.getDeep());
        return vo;
    }

    @Override
    public void updateProjectSpaceName(Long spaceId, String newName) {
        if (spaceId == null || newName == null) {
            return;
        }
        BaseSpace space = this.getById(spaceId);
        if (space == null) {
            return;
        }
        space.setName(newName);
        space.setUpdatedBy(SecurityUtils.getUsername());
        space.setUpdateTime(LocalDateTime.now());
        this.updateById(space);
    }

    @Override
    public boolean isLeafSpace(Long spaceId) {
        if (spaceId == null) {
            return true;
        }
        return this.count(new LambdaQueryWrapper<BaseSpace>().eq(BaseSpace::getParentId, spaceId)) == 0;
    }
}
