package com.lanyuanxiaoyao.service.web.controller;

import cn.hutool.core.map.MapUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.lanyuanxiaoyao.service.web.controller.base.AmisCrudResponse;
import com.lanyuanxiaoyao.service.web.controller.base.AmisMapResponse;
import com.lanyuanxiaoyao.service.web.controller.base.AmisResponse;
import com.lanyuanxiaoyao.service.web.controller.base.BaseController;
import com.lanyuanxiaoyao.service.web.entity.CloudServiceVO;
import java.util.Map;
import org.apache.curator.x.discovery.ServiceInstance;
import org.eclipse.collections.api.block.function.Function;
import org.eclipse.collections.api.factory.Lists;
import org.eclipse.collections.api.factory.Maps;
import org.eclipse.collections.api.list.ImmutableList;
import org.eclipse.collections.api.list.MutableList;
import org.eclipse.collections.api.map.MutableMap;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.cloud.client.discovery.DiscoveryClient;
import org.springframework.cloud.zookeeper.discovery.ZookeeperInstance;
import org.springframework.cloud.zookeeper.discovery.ZookeeperServiceInstance;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

/**
 * 云页面
 *
 * @author lanyuanxiaoyao
 * @date 2023-04-30
 */
@RestController
@RequestMapping("cloud")
public class CloudController extends BaseController {
    private static final Logger logger = LoggerFactory.getLogger(CloudController.class);

    private final DiscoveryClient client;

    public CloudController(DiscoveryClient client) {
        this.client = client;
    }

    private ImmutableList<CloudServiceVO.Service> services() {
        return Lists.immutable.ofAll(client.getServices())
                .flatCollect(client::getInstances)
                .collect(instance -> {
                    CloudServiceVO.Service service = new CloudServiceVO.Service(
                            instance.getInstanceId(),
                            instance.getServiceId(),
                            instance.getHost(),
                            instance.getPort(),
                            instance.isSecure(),
                            instance.getUri().toString(),
                            Maps.immutable.ofAll(instance.getMetadata())
                    );
                    if (instance instanceof ZookeeperServiceInstance) {
                        ZookeeperServiceInstance zookeeperServiceInstance = (ZookeeperServiceInstance) instance;
                        ServiceInstance<ZookeeperInstance> serviceInstance = zookeeperServiceInstance.getServiceInstance();
                        if (ObjectUtil.isNotNull(serviceInstance)) {
                            service.setServiceUpTime(serviceInstance.getRegistrationTimeUTC());
                            service.setStatus(serviceInstance.getPayload().getMetadata().getOrDefault("instance_status", ""));
                        }
                    }
                    return service;
                });
    }

    private ImmutableList<CloudServiceVO> serviceVOS(Function<CloudServiceVO.Service, String> groupByField) {
        return services()
                .groupBy(groupByField)
                .toMap()
                .collectValues((serviceId, services) -> new CloudServiceVO(serviceId, services.toSortedListBy(CloudServiceVO.Service::getServiceUpTime).toImmutable()))
                .valuesView()
                .toSortedListBy(CloudServiceVO::getName)
                .toImmutable();
    }

    @GetMapping("list")
    public AmisCrudResponse list() {
        ImmutableList<CloudServiceVO> serviceVOS = serviceVOS(CloudServiceVO.Service::getServiceId);
        return AmisResponse.responseCrudData(serviceVOS, serviceVOS.size());
    }

    @GetMapping("list_ip")
    public AmisCrudResponse listIp() {
        ImmutableList<CloudServiceVO> serviceVOS = serviceVOS(CloudServiceVO.Service::getHost);
        return AmisResponse.responseCrudData(serviceVOS, serviceVOS.size());
    }

    @GetMapping("deploy_plan")
    public AmisMapResponse deployPlan() {
        ImmutableList<CloudServiceVO.Service> services = services();
        ImmutableList<String> deployExists = services.collect(service -> StrUtil.format("{}-{}", service.getServiceId(), service.getHost()));
        ImmutableList<String> serviceIds = services.collect(CloudServiceVO.Service::getServiceId).distinct().toSortedList().toImmutable();
        ImmutableList<String> hosts = services.collect(CloudServiceVO.Service::getHost).distinct().toSortedList().toImmutable();
        MutableList<MutableMap<String, Object>> data = Lists.mutable.empty();
        serviceIds.forEach(serviceId -> {
            MutableMap<String, Object> item = Maps.mutable.empty();
            item.put("service", serviceId);
            hosts.forEach(host -> item.put(host.replaceAll("\\.", "_"), deployExists.contains(StrUtil.format("{}-{}", serviceId, host)) ? "" : null));
            data.add(item);
        });
        ImmutableList<Map<String, Object>> columns =
                Lists.immutable.of(MapUtil.<String, Object>builder()
                                .put("name", "service")
                                .put("label", "服务")
                                .put("width", 250)
                                .build())
                        .newWithAll(hosts.collect(host -> {
                            String key = host.replaceAll("\\.", "_");
                            return MapUtil.<String, Object>builder()
                                    .put("name", key)
                                    .put("label", host)
                                    .put("align", "center")
                                    .put("classNameExpr", "<%= data['" + key + "'] === '' ? 'bg-success' : '' %>")
                                    .put("type", "tpl")
                                    .put("tpl", "${" + key + "}")
                                    .build();
                        }));
        return AmisResponse.responseMapData(
                MapUtil.<String, Object>builder()
                        .put("type", "service")
                        .put("data", MapUtil.builder()
                                .put("rows", data)
                                .build())
                        .put("silentPolling", true)
                        .put("body", MapUtil.builder()
                                .put("type", "table")
                                .put("title", "部署分布")
                                .put("source", "$rows")
                                .put("columns", columns)
                                .build())
                        .build()
        );
    }

    @GetMapping("heart")
    public AmisMapResponse heart() {
        return AmisResponse.responseMapData("status", true);
    }
}
