/*
 * Copyright 1999-2018 Alibaba Group Holding Ltd.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.alibaba.nacos.core.controller.v2;

import com.alibaba.nacos.api.annotation.NacosApi;
import com.alibaba.nacos.api.exception.NacosException;
import com.alibaba.nacos.api.exception.api.NacosApiException;
import com.alibaba.nacos.api.model.v2.ErrorCode;
import com.alibaba.nacos.api.model.v2.Result;
import com.alibaba.nacos.auth.annotation.Secured;
import com.alibaba.nacos.common.model.RestResult;
import com.alibaba.nacos.common.model.RestResultUtils;
import com.alibaba.nacos.common.utils.StringUtils;
import com.alibaba.nacos.core.cluster.Member;
import com.alibaba.nacos.api.common.NodeState;
import com.alibaba.nacos.core.controller.compatibility.Compatibility;
import com.alibaba.nacos.core.model.request.LookupUpdateRequest;
import com.alibaba.nacos.core.service.NacosClusterOperationService;
import com.alibaba.nacos.core.utils.Commons;
import com.alibaba.nacos.plugin.auth.constant.ActionTypes;
import com.alibaba.nacos.plugin.auth.constant.ApiType;
import com.alibaba.nacos.plugin.auth.constant.SignType;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import java.util.Collection;
import java.util.List;
import java.util.Locale;

/**
 * Cluster communication interface v2.
 *
 * @author wuzhiguo
 */
@NacosApi
@RestController
@RequestMapping(Commons.NACOS_CORE_CONTEXT_V2 + "/cluster")
@Deprecated
public class NacosClusterControllerV2 {
    
    private final NacosClusterOperationService nacosClusterOperationService;
    
    public NacosClusterControllerV2(NacosClusterOperationService nacosClusterOperationService) {
        this.nacosClusterOperationService = nacosClusterOperationService;
    }
    
    @GetMapping(value = "/node/self")
    @Secured(action = ActionTypes.READ, resource = "nacos/admin", signType = SignType.CONSOLE)
    @Compatibility(apiType = ApiType.ADMIN_API, alternatives = "GET {contextPath:nacos}/v3/admin/core/cluster/node/self")
    public Result<Member> self() {
        return Result.success(nacosClusterOperationService.self());
    }
    
    /**
     * The console displays the list of cluster members.
     *
     * @param address match address
     * @param state   match state
     * @return members that matches condition
     */
    @GetMapping(value = "/node/list")
    @Secured(action = ActionTypes.READ, resource = "nacos/admin", signType = SignType.CONSOLE)
    @Compatibility(apiType = ApiType.ADMIN_API, alternatives = "GET {contextPath:nacos}/v3/admin/core/cluster/node/list")
    public Result<Collection<Member>> listNodes(@RequestParam(value = "address", required = false) String address,
            @RequestParam(value = "state", required = false) String state) throws NacosException {
        
        NodeState nodeState = null;
        if (StringUtils.isNoneBlank(state)) {
            try {
                nodeState = NodeState.valueOf(state.toUpperCase(Locale.ROOT));
            } catch (IllegalArgumentException e) {
                throw new NacosApiException(HttpStatus.BAD_REQUEST.value(), ErrorCode.ILLEGAL_STATE,
                        "Illegal state: " + state);
            }
        }
        return Result.success(nacosClusterOperationService.listNodes(address, nodeState));
    }
    
    @GetMapping(value = "/node/self/health")
    @Secured(action = ActionTypes.READ, resource = "nacos/admin", signType = SignType.CONSOLE)
    @Compatibility(apiType = ApiType.ADMIN_API, alternatives = "GET {contextPath:nacos}/v3/admin/core/cluster/node/self/health")
    public Result<String> selfHealth() {
        return Result.success(nacosClusterOperationService.selfHealth());
    }
    
    // The client can get all the nacos node information in the current
    // cluster according to this interface
    
    /**
     * Other nodes return their own metadata information.
     *
     * @param nodes List of {@link Member}
     * @return {@link RestResult}
     */
    @PutMapping(value = "/node/list")
    @Secured(action = ActionTypes.WRITE, resource = "nacos/admin", signType = SignType.CONSOLE)
    @Compatibility(apiType = ApiType.ADMIN_API, alternatives = "PUT {contextPath:nacos}/v3/admin/core/cluster/node/list")
    public Result<Boolean> updateNodes(@RequestBody List<Member> nodes) throws NacosApiException {
        if (nodes == null || nodes.size() == 0) {
            throw new NacosApiException(HttpStatus.BAD_REQUEST.value(), ErrorCode.PARAMETER_MISSING,
                    "required parameter 'nodes' is missing");
        }
        return Result.success(nacosClusterOperationService.updateNodes(nodes));
    }
    
    /**
     * Addressing mode switch.
     *
     * @param request {@link LookupUpdateRequest}
     * @return {@link RestResult}
     */
    @PutMapping(value = "/lookup")
    @Secured(action = ActionTypes.WRITE, resource = "nacos/admin", signType = SignType.CONSOLE)
    @Compatibility(apiType = ApiType.ADMIN_API, alternatives = "PUT {contextPath:nacos}/v3/admin/core/cluster/lookup")
    public Result<Boolean> updateLookup(LookupUpdateRequest request) throws NacosException {
        if (request == null || request.getType() == null) {
            throw new NacosApiException(HttpStatus.BAD_REQUEST.value(), ErrorCode.PARAMETER_MISSING,
                    "required parameter 'type' is missing");
        }
        return Result.success(nacosClusterOperationService.updateLookup(request));
    }
    
    /**
     * member leave.
     *
     * @param addresses member ip list, example [ip1:port1,ip2:port2,...]
     * @return {@link RestResult}
     * @throws Exception throw {@link Exception}
     */
    @DeleteMapping("/nodes")
    @Secured(action = ActionTypes.WRITE, resource = "nacos/admin", signType = SignType.CONSOLE)
    @Compatibility(apiType = ApiType.ADMIN_API)
    public RestResult<Void> deleteNodes(@RequestParam("addresses") List<String> addresses) throws Exception {
        return RestResultUtils.failed(405, null, "DELETE /v2/core/cluster/nodes API not allow to use temporarily.");
        
    }
    
}
