package me.qwq.doghouse.service;

import java.util.Set;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import jakarta.servlet.http.HttpServletRequest;
import me.qwq.doghouse.entity.config.NetworkConfig;
import me.qwq.doghouse.pojo.bo.CidrBlock;
import me.qwq.doghouse.util.IPUtils;

@Service
public class IpService {
    
    @Autowired
    NetworkConfig networkConfig;
    
    static Set<String> LOCALHOST = Set.of(IPUtils.LOCALHOSTS);
    
    public String getClientIp(HttpServletRequest request) {
        
        Set<String> trustedIps = networkConfig.getTrustedIpList();
        Set<CidrBlock> trustedCidrs = networkConfig.getTrustedCidrBlockList();
        
        trustedIps.addAll(LOCALHOST);
        
        String remoteAddr = IPUtils.stripZoneId(request.getRemoteAddr());
        boolean trusted = false;
        if (trustedIps.contains(remoteAddr)) {
            trusted = true;
        }
        else {
            for (CidrBlock block : trustedCidrs) {
                if (block.contains(remoteAddr)) {
                    trusted = true;
                    break;
                }
            }
        }
        if (trusted) {
            // extract forward ip from header
            for (String headerName : IPUtils.HEADERS) {
                String value = request.getHeader(headerName);
                if (value == null) {
                    continue;
                }
                for (String chainIp : value.split(",")) {
                    if (chainIp.isBlank() || "unknown".equalsIgnoreCase(chainIp)) {
                        continue;
                    }
                    // 对于通过多个代理的情况，取第一个为真实 IP
                    value = chainIp;
                    break;
                }
                value = IPUtils.stripZoneId(value);
                if (IPUtils.isValidIp(value)) return value;
            }
        }
        
        if (IPUtils.isLocalhost(remoteAddr)) {
            String localIp = IPUtils.getLocalMachineIp();
            if (localIp != null) {
                return localIp;
            }
        }
        return remoteAddr;
    }

}
