package com.springboot.cloud.auth.authentication.service.impl;

import com.springboot.cloud.auth.authentication.entity.License;
import com.springboot.cloud.auth.authentication.entity.Popedom;
import com.springboot.cloud.auth.authentication.provider.PopedomProvider;
import com.springboot.cloud.auth.authentication.service.NewMvcRequestMatcher;
import com.springboot.cloud.auth.authentication.service.PopedomService;
import com.springboot.cloud.common.core.entity.vo.Result;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.access.ConfigAttribute;
import org.springframework.security.access.SecurityConfig;
import org.springframework.security.web.servlet.util.matcher.MvcRequestMatcher;
import org.springframework.security.web.util.matcher.RequestMatcher;
import org.springframework.stereotype.Service;
import org.springframework.web.servlet.handler.HandlerMappingIntrospector;

import javax.servlet.http.HttpServletRequest;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 处理资源数据，提高效率有三种方案：
 * 1、内存储存处理
 * 2、redis存储处理
 * 3、直接调用服务
 * 第一种方案需要结合消息处理，每次增量读取新增的数据
 */

@Service
@Slf4j
public class PopedomServiceImpl implements PopedomService {

    @Autowired
    private HandlerMappingIntrospector mvcHandlerMappingIntrospector;

    @Autowired
    private PopedomProvider popedomProvider;

    /**
     * 系统中权限分组集合
     * key:companyId,value:{key:url,value:config}
     */
    private static final Map<String, Map<RequestMatcher, ConfigAttribute>> popedomConfigAttributes = new HashMap<>();

    @Override
    public synchronized void savePopedom(List<Popedom> popedoms) {
        popedoms.stream().forEach(popedom -> {
            if (popedomConfigAttributes.containsKey(popedom.getCompanyId())) {
                //如果包含company对应的权限表，则更新
                Map<RequestMatcher, ConfigAttribute> attributeMap = popedomConfigAttributes.get(popedom.getCompanyId());
                attributeMap.put(this.newMvcRequestMatcher(popedom.getUrl()), new SecurityConfig(popedom.getId()));
            } else {
                //如果不包含company对应的权限表，则新增
                Map<RequestMatcher, ConfigAttribute> map = new HashMap<>();
                map.put(this.newMvcRequestMatcher(popedom.getUrl()), new SecurityConfig(popedom.getId()));
                popedomConfigAttributes.put(popedom.getCompanyId(), map);
            }
        });
        log.info("popedomConfigAttributes size:{}", popedomConfigAttributes.size());
    }

    @Override
    public synchronized void removePopedom(Popedom popedom) {
        if (popedomConfigAttributes.containsKey(popedom.getCompanyId())) {
            Map<RequestMatcher, ConfigAttribute> attributeMap = popedomConfigAttributes.get(popedom.getCompanyId());
            attributeMap.remove(this.newMvcRequestMatcher(popedom.getUrl()));
        }
        log.info("resourceConfigAttributes size:{}", popedomConfigAttributes.size());
    }

    @Override
    public synchronized void loadPopedom() {
        Result<List<Popedom>> resourcesResult = popedomProvider.popedoms();
        if (resourcesResult.isFail()) {
            System.exit(1);
        }
        List<Popedom> popedoms = resourcesResult.getData();
        //先根据公司分组，然后放入内存
        Map<String, Map<RequestMatcher, ConfigAttribute>> map = popedoms.stream().filter(a -> null != a.getUrl() && !a.getUrl().equals("")).collect(Collectors.groupingBy(Popedom::getCompanyId, Collectors.toMap(a -> newMvcRequestMatcher(a.getUrl()), a -> new SecurityConfig(a.getId()))));
        popedomConfigAttributes.putAll(map);
        log.debug("init resourceConfigAttributes:{}", popedomConfigAttributes);
    }

    @Override
    public List<ConfigAttribute> findConfigAttributesByUrl(HttpServletRequest authRequest) {
        String companyId = Optional.ofNullable(authRequest.getParameter("companyId")).orElseGet(String::new);
//        String companyId = Optional.ofNullable(UserContextHolder.getInstance().getCurrentCompany()).orElseGet(String::new);
        if (popedomConfigAttributes.containsKey(companyId)) {
            Map<RequestMatcher, ConfigAttribute> attributeMap = popedomConfigAttributes.get(companyId);
            return attributeMap.keySet().stream()
                    .filter(requestMatcher -> requestMatcher.matches(authRequest))
                    .map(requestMatcher -> attributeMap.get(requestMatcher))
                    .peek(urlConfigAttribute -> log.debug("url在资源池中配置：{}", urlConfigAttribute.getAttribute()))
                    .collect(Collectors.toList());
        } else {
            return Collections.emptyList();
        }
    }

    @Override
    public List<Popedom> queryByUsername(String companyId, String username) {
        return popedomProvider.popedoms(companyId, username).getData();
    }

    @Override
    public boolean license(String companyId, String applicationCode) {
        Result<License> licenseResult = popedomProvider.license(companyId, applicationCode);
        if (licenseResult.isFail()) {
            return false;
        }
        License data = licenseResult.getData();
        if (null == data) {
            return false;
        }
        if (data.isForever()) {
            return true;
        }
        if (data.getExpireDate().getTime() > new Date().getTime()) {
            return true;
        } else {
            return false;
        }
    }

    /**
     * 创建RequestMatcher
     *
     * @param url
     * @return
     */
    private MvcRequestMatcher newMvcRequestMatcher(String url) {
        return new NewMvcRequestMatcher(mvcHandlerMappingIntrospector, url);
    }
}