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

import com.alibaba.csp.sentinel.dashboard.client.SentinelApiClient;
import com.alibaba.csp.sentinel.dashboard.datasource.entity.gateway.GatewayFlowRuleEntity;
import com.alibaba.csp.sentinel.dashboard.datasource.entity.rule.*;
import com.alibaba.csp.sentinel.dashboard.repository.gateway.InMemGatewayFlowRuleStore;
import com.alibaba.csp.sentinel.dashboard.repository.rule.InMemoryRuleRepositoryAdapter;
import com.alibaba.csp.sentinel.dashboard.repository.rule.RuleRepository;
import com.alibaba.csp.sentinel.dashboard.rule.DynamicRuleProvider;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Component;

import java.util.List;
import java.util.stream.Collectors;

/**
 * 执行预加载,将nacos上的config保存到内存中
 *
 * @author Clay
 * @date 2022/11/13
 */
@Component
public class InitNacosConfig {

    private final Logger logger = LoggerFactory.getLogger(InitNacosConfig.class);

    @Autowired
    private SentinelApiClient sentinelApiClient;

    @Autowired
    private InMemoryRuleRepositoryAdapter<FlowRuleEntity> repositoryFlowRuleEntity;


    @Autowired
    private RuleRepository<AuthorityRuleEntity, Long> repositoryAuthorityRuleEntity;


    @Autowired
    private RuleRepository<DegradeRuleEntity, Long> repositoryDegradeRuleEntity;


    @Autowired
    private RuleRepository<SystemRuleEntity, Long> repositorySystemRuleEntity;


    @Autowired
    private RuleRepository<ParamFlowRuleEntity, Long> repositoryParamFlowRuleEntity;


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


    @Autowired
    @Qualifier("paramFlowRuleNacosProvider")
    private DynamicRuleProvider<List<ParamFlowRuleEntity>> paramFlowRuleNacosProvider;

    @Autowired
    @Qualifier("systemRuleNacosProvider")
    private DynamicRuleProvider<List<SystemRuleEntity>> systemRuleNacosProvider;


    @Autowired
    @Qualifier("degradeRuleNacosProvider")
    private DynamicRuleProvider<List<DegradeRuleEntity>> degradeRuleNacosProvider;

    @Autowired
    @Qualifier("authorityRuleNacosProvider")
    private DynamicRuleProvider<List<AuthorityRuleEntity>> authorityRuleNacosProvider;


    /**
     * 初始化nacos的配置
     * @param app
     * @param ip
     * @param port
     */
    public void initNacos(String app, String ip, Integer port){
        //try {
        //    publishFlowRules(app,ip,port);
        //    publishDegradeRules(app,ip,port);
        //    publishSystemRules(app,ip,port);
        //    publishAuthorityRules(app,ip,port);
        //    publishParamFlowRules(app,ip,port);
        //}catch (Exception e){
        //    logger.error("init error app : {}",app);
        //}
    }


    private void publishFlowRules(String app, String ip, Integer port) throws Exception {
        List<FlowRuleEntity> rules = flowRuleNacosProvider.getRules(app);
        rules = filterFlowRule(app,ip,port,rules);
        rules = repositoryFlowRuleEntity.saveAll(rules);
        sentinelApiClient.setInitRulesAsync(app, ip, port, SentinelApiClient.FLOW_RULE_TYPE,rules);
    }


    private void publishDegradeRules(String app, String ip, Integer port) throws Exception {
        List<DegradeRuleEntity> rules = degradeRuleNacosProvider.getRules(app);
        rules = filterDegradeRule(app,ip,port,rules);
        rules = repositoryDegradeRuleEntity.saveAll(rules);
        sentinelApiClient.setInitRulesAsync(app, ip, port, SentinelApiClient.DEGRADE_RULE_TYPE,rules);
    }


    private void publishSystemRules(String app, String ip, Integer port) throws Exception {
        List<SystemRuleEntity> rules = systemRuleNacosProvider.getRules(app);
        rules = filterSystemRule(app,ip,port,rules);
        rules = repositorySystemRuleEntity.saveAll(rules);
        sentinelApiClient.setInitRulesAsync(app, ip, port, SentinelApiClient.SYSTEM_RULE_TYPE,rules);
    }


    private void publishAuthorityRules(String app, String ip, Integer port) throws Exception {
        List<AuthorityRuleEntity> rules = authorityRuleNacosProvider.getRules(app);
        rules = filterAuthorityRule(app,ip,port,rules);
        rules = repositoryAuthorityRuleEntity.saveAll(rules);
        sentinelApiClient.setInitRulesAsync(app, ip, port, SentinelApiClient.AUTHORITY_TYPE,rules);
    }


    private void publishParamFlowRules(String app, String ip, Integer port) throws Exception {
        List<ParamFlowRuleEntity> rules = paramFlowRuleNacosProvider.getRules(app);
        rules = filterParamFlowRule(app,ip,port,rules);
        rules = repositoryParamFlowRuleEntity.saveAll(rules);
        sentinelApiClient.setParamFlowRuleOfMachine(app, ip, port, rules);
    }


    private List<FlowRuleEntity> filterFlowRule(String app, String ip, Integer port, List<FlowRuleEntity> rules){
       return rules.stream()
               .filter(entity-> app.equals(entity.getApp())&&ip.equals(entity.getIp())&&port.equals(entity.getPort()))
               .collect(Collectors.toList());
    }

    private List<DegradeRuleEntity> filterDegradeRule(String app, String ip, Integer port, List<DegradeRuleEntity> rules){
       return rules.stream()
               .filter(entity-> app.equals(entity.getApp())&&ip.equals(entity.getIp())&&port.equals(entity.getPort()))
               .collect(Collectors.toList());
    }

    private List<SystemRuleEntity> filterSystemRule(String app, String ip, Integer port, List<SystemRuleEntity> rules){
       return rules.stream()
               .filter(entity-> app.equals(entity.getApp())&&ip.equals(entity.getIp())&&port.equals(entity.getPort()))
               .collect(Collectors.toList());
    }

    private List<AuthorityRuleEntity> filterAuthorityRule(String app, String ip, Integer port, List<AuthorityRuleEntity> rules){
       return rules.stream()
               .filter(entity-> app.equals(entity.getApp())&&ip.equals(entity.getIp())&&port.equals(entity.getPort()))
               .collect(Collectors.toList());
    }

    private List<ParamFlowRuleEntity> filterParamFlowRule(String app, String ip, Integer port, List<ParamFlowRuleEntity> rules){
       return rules.stream()
               .filter(entity-> app.equals(entity.getApp())&&ip.equals(entity.getIp())&&port.equals(entity.getPort()))
               .collect(Collectors.toList());
    }

}
