package com.sunyard.chsm.config;


import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.sunyard.chsm.constant.ParamConfKeyConstant;
import com.sunyard.chsm.enums.EnableStatus;
import com.sunyard.chsm.mapper.IpWhitelisttMapper;
import com.sunyard.chsm.mapper.ParamConfMapper;
import com.sunyard.chsm.model.entity.IpWhitelist;
import com.sunyard.chsm.model.entity.ParamConf;
import com.sunyard.chsm.utils.IpUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;
import org.springframework.web.filter.OncePerRequestFilter;

import javax.annotation.Resource;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

/**
 * @author liulu
 * @since 2024/12/2
 */
@Slf4j
@Component
public class IpFilter extends OncePerRequestFilter implements ApplicationRunner {

    public static List<String> whiteIps = new ArrayList<>();
    public static Boolean enableWhiteIp = false;

    @Resource
    private IpWhitelisttMapper ipWhitelisttMapper;
    @Resource
    private ParamConfMapper paramConfMapper;


    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain) throws ServletException, IOException {
        if (enableWhiteIp && CollectionUtils.isEmpty(whiteIps)) {
            syncWhiteIps();
        }
        String ip = IpUtils.getIpAddress(request);
        if (!enableWhiteIp || CollectionUtils.isEmpty(whiteIps) || whiteIps.contains(ip)) {
            chain.doFilter(request, response);
            return;
        }
        logger.warn("forbidden for ip: " + ip);
        response.setStatus(HttpServletResponse.SC_FORBIDDEN);
        response.setContentType(MediaType.TEXT_PLAIN_VALUE);
        response.getWriter().println("this ip is forbidden");
        response.getWriter().flush();
    }


    @Override
    public void run(ApplicationArguments args) throws Exception {
        Executors.newSingleThreadScheduledExecutor()
                .scheduleWithFixedDelay(() -> {

                    ParamConf conf = paramConfMapper.selectByKey(ParamConfKeyConstant.IP_WHITELIST_SWITCH);
                    if (conf != null) {
                        enableWhiteIp = Objects.equals("true", conf.getValue());
                    }
                    if (enableWhiteIp) {
                        syncWhiteIps();
                    }
                }, 1L, 5L, TimeUnit.MINUTES);
    }


    private void syncWhiteIps() {
        List<IpWhitelist> list = ipWhitelisttMapper.selectList(
                new LambdaQueryWrapper<IpWhitelist>()
                        .eq(IpWhitelist::getScope, "global")
                        .eq(IpWhitelist::getStatus, EnableStatus.ENABLED.getCode())
        );
        whiteIps = list.stream().map(IpWhitelist::getIp).collect(Collectors.toList());
    }

}
