package com.yuchen.saas.park.api.commons;

import lombok.Data;
import lombok.RequiredArgsConstructor;
import lombok.val;

import javax.validation.constraints.NotEmpty;
import javax.validation.constraints.Positive;
import javax.validation.constraints.PositiveOrZero;
import java.util.*;

import static java.util.function.UnaryOperator.identity;
import static java.util.stream.Collectors.*;

@Data
@RequiredArgsConstructor(staticName = "of")
public class IdHierarchyTree {
    @PositiveOrZero
    private final long id;
    private List<IdHierarchyTree> children = new ArrayList<>();

    public static Map<@PositiveOrZero Long, IdHierarchyTree> from(List<IdTree> list) {
        val map = list.stream()
          .map(o -> new Long[]{o.getId(), o.getParentId()})
          .flatMap(Arrays::stream)
          .map(IdHierarchyTree::of)
          .distinct()
          .collect(toMap(IdHierarchyTree::getId, identity()));

        list.forEach(o -> map.get(o.getParentId()).getChildren().add(map.get(o.getId())));

        return map;
    }

    /**
     * @return 包含自身 {@link #id}
     */
    @NotEmpty
    public static Set<@Positive Long> listIdRecursiveById(Map<@PositiveOrZero Long, IdHierarchyTree> map, @PositiveOrZero long id) {
        val result = new HashSet<Long>();
        recursive(id, result, map);
        return result;
    }

    /**
     * @return 包含自身 {@link #id}
     */
    @NotEmpty
    public static Set<@Positive Long> listIdRecursiveById(List<IdTree> list, @PositiveOrZero long id) {
        val map = from(list);
        val result = new HashSet<Long>();
        recursive(id, result, map);
        return result;
    }

    private static void recursive(@PositiveOrZero long rootId, Set<@PositiveOrZero Long> result, Map<@PositiveOrZero Long, IdHierarchyTree> map) {
        result.add(rootId);

        map.get(rootId).getChildren()
          .stream()
          .map(IdHierarchyTree::getId)
          .forEach(id -> recursive(id, result, map));
    }
}
