--
-- Licensed to the Apache Software Foundation (ASF) under one or more
-- contributor license agreements.  See the NOTICE file distributed with
-- this work for additional information regarding copyright ownership.
-- The ASF licenses this file to You 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.
--
local core = require("apisix.core")
local config_util = require("apisix.core.config_util")
local get_routes = require("apisix.router").http_routes
local get_services = require("apisix.http.service").services
local get_plugin_configs = require("apisix.plugin_config").plugin_configs
local get_consumers = require("apisix.consumer").consumers
local get_consumer_groups = require("apisix.consumer_group").consumer_groups
local get_global_rules = require("apisix.global_rules").global_rules
local apisix_upstream = require("apisix.upstream")
local resource = require("apisix.admin.resource")
local tostring = tostring
local ipairs = ipairs


local function check_conf(id, conf, need_id)
    local ok, err = apisix_upstream.check_upstream_conf(conf)
    if not ok then
        return nil, {error_msg = err}
    end

    return true
end


local function encrypt_conf(id, conf)
    apisix_upstream.encrypt_conf(conf)
end


local function up_id_in_plugins(plugins, up_id)
    if plugins and plugins["traffic-split"]
        and plugins["traffic-split"].rules then

        for _, rule in ipairs(plugins["traffic-split"].rules) do
            local plugin_upstreams = rule.weighted_upstreams
            for _, plugin_upstream in ipairs(plugin_upstreams) do
                if plugin_upstream.upstream_id
                    and tostring(plugin_upstream.upstream_id) == up_id then
                     return true
                end
            end
        end

        return false
    end
end


local function check_resources_reference(resources, up_id,
                                         only_check_plugin, resources_name)
    if resources then
        for _, resource in config_util.iterate_values(resources) do
            if resource and resource.value then
                if up_id_in_plugins(resource.value.plugins, up_id) then
                    return {error_msg = "can not delete this upstream,"
                                        .. " plugin in "
                                        .. resources_name .. " ["
                                        .. resource.value.id
                                        .. "] is still using it now"}
                end

                if not only_check_plugin and resource.value.upstream_id
                    and tostring(resource.value.upstream_id) == up_id then
                     return {error_msg = "can not delete this upstream, "
                                         .. resources_name .. " [" .. resource.value.id
                                         .. "] is still using it now"}
                end
            end
        end
    end
end


local function delete_checker(id)
    local routes = get_routes()
    local err_msg = check_resources_reference(routes, id, false, "route")
    if err_msg then
        return 400, err_msg
    end

    local services, services_ver = get_services()
    core.log.info("services: ", core.json.delay_encode(services, true))
    core.log.info("services_ver: ", services_ver)
    local err_msg = check_resources_reference(services, id, false, "service")
    if err_msg then
        return 400, err_msg
    end

    local plugin_configs = get_plugin_configs()
    local err_msg = check_resources_reference(plugin_configs, id, true, "plugin_config")
    if err_msg then
        return 400, err_msg
    end

    local consumers = get_consumers()
    local err_msg = check_resources_reference(consumers, id, true, "consumer")
    if err_msg then
        return 400, err_msg
    end

    local consumer_groups = get_consumer_groups()
    local err_msg = check_resources_reference(consumer_groups, id, true, "consumer_group")
    if err_msg then
        return 400, err_msg
    end

    local global_rules = get_global_rules()
    err_msg = check_resources_reference(global_rules, id, true, "global_rules")
    if err_msg then
        return 400, err_msg
    end

    return nil, nil
end


return resource.new({
    name = "upstreams",
    kind = "upstream",
    schema = core.schema.upstream,
    checker = check_conf,
    encrypt_conf = encrypt_conf,
    delete_checker = delete_checker
})
