package com.alibaba.csp.sentinel.dashboard.rule.nacos.processor.impl;

import com.alibaba.csp.sentinel.dashboard.client.SentinelApiClient;
import com.alibaba.csp.sentinel.dashboard.datasource.entity.rule.FlowRuleEntity;
import com.alibaba.csp.sentinel.dashboard.discovery.MachineInfo;
import com.alibaba.csp.sentinel.dashboard.repository.rule.InMemoryRuleRepositoryAdapter;
import com.alibaba.csp.sentinel.dashboard.rule.DynamicRuleProvider;
import com.alibaba.csp.sentinel.dashboard.rule.DynamicRulePublisher;
import com.alibaba.csp.sentinel.dashboard.rule.nacos.processor.BaseProcessor;
import com.alibaba.csp.sentinel.dashboard.rule.nacos.processor.NacosPostProcessor;
import com.alibaba.csp.sentinel.dashboard.rule.nacos.util.NacosUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Service;

import java.util.List;
import java.util.concurrent.TimeUnit;

/**
 * @author Clay
 * @date 2022/11/14
 */
@Service
public class FlowNacosPostProcessor extends BaseProcessor implements NacosPostProcessor {

    @Autowired
    private InMemoryRuleRepositoryAdapter<FlowRuleEntity> repository;

    @Autowired
    @Qualifier("flowRuleNacosProvider")
    private DynamicRuleProvider<List<FlowRuleEntity>> ruleProvider;

    @Autowired
    @Qualifier("flowRuleNacosPublisher")
    private DynamicRulePublisher<List<FlowRuleEntity>> rulePublisher;

    @Override
    public void initPostProcessor(String app, String ip, Integer port) throws Exception {
        List<FlowRuleEntity> rules = ruleProvider.getRules(app);
        rules = NacosUtils.filterSelf(app,ip,port,rules);
        rules = repository.saveAll(rules);
        sentinelApiClient.setInitRulesAsync(app, ip, port, SentinelApiClient.FLOW_RULE_TYPE,rules);
    }

    @Override
    public void initClusterProcessor(String app, String ip, Integer port) throws Exception {
        List<FlowRuleEntity> rules = ruleProvider.getRules(app);
        rules = repository.saveAll(rules);
        sentinelApiClient.setInitRulesAsync(app, ip, port, SentinelApiClient.FLOW_RULE_TYPE,rules);
    }

    @Override
    public boolean publishRules(String app, String ip, Integer port, Class<?> clazz) throws Exception {
        if (clazz != FlowRuleEntity.class){
            return false;
        }
        //从nacos上获取全部的
        List<FlowRuleEntity> rules = ruleProvider.getRules(app);
        //排除自身的规则
        rules = NacosUtils.filterOther(app,ip,port,rules);
        //拿到自身新的规则
        List<FlowRuleEntity> newRules = repository.findAllByMachine(MachineInfo.of(app, ip, port));
        //合并规则
        rules.addAll(newRules);
        //发布到nacos
        rulePublisher.publish(app, newRules);
        sentinelApiClient.setFlowRuleOfMachineAsync(app, ip, port, newRules).get(5000, TimeUnit.MILLISECONDS);
        return true;
    }

    @Override
    public boolean publishClusterRules(String app, String ip, Integer port, Class<?> clazz) throws Exception {
        if (clazz != FlowRuleEntity.class){
            return false;
        }
        List<FlowRuleEntity> rules = repository.findAllByMachine(MachineInfo.of(app, ip, port));
        getAppInfo(app).forEach(info-> sentinelApiClient.setFlowRuleOfMachineAsync(info.getApp(), info.getIp(), info.getPort(), rules));
        rulePublisher.publish(app, rules);
        return true;
    }

    @Override
    public <T> List<T> getRules(String app, String ip, Integer port, Class<?> clazz) throws Exception {
        if (clazz != FlowRuleEntity.class){
            return null;
        }
        List<FlowRuleEntity> rules = ruleProvider.getRules(app);
        return (List<T>) NacosUtils.filterSelf(app, ip, port, rules);
    }

    @Override
    public <T> List<T> getClusterRules(String app, String ip, Integer port, Class<?> clazz) throws Exception {
        if (clazz != FlowRuleEntity.class){
            return null;
        }
        return (List<T>) ruleProvider.getRules(app);
    }
}
