package com.backendsys.utils;

import java.io.IOException;
import java.net.*;
import java.security.MessageDigest;
import java.text.SimpleDateFormat;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Date;
import java.util.Random;
import java.util.UUID;

import cn.hutool.core.date.DateUtil;
import cn.hutool.core.io.FileUtil;
import com.backendsys.exception.CustException;
import jakarta.servlet.http.HttpServletRequest;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.env.Environment;
import org.springframework.stereotype.Component;

@Component
public class CommonUtil {

    @Autowired
    private Environment env;

    //@Autowired
    //private static TokenUtil tokenService;

    // 以上引用会报错：
    // Cannot invoke \"com.backendsys.modules.common.config.Security.utils.TokenUtil.getTokenInfo(jakarta.servlet.http.HttpServletRequest)\" because \"com.backendsys.utils.CommonUtil.tokenService\" is null
    // 工具类无法直接用，得写 set 方法，如下：

    //private static TokenUtil tokenService;
    //@Autowired
    //public void setTokenService(TokenUtil tokenService) {
    //    this.tokenService = tokenService;
    //}

    /**
     * 获取自身 ip
     * @param request
     */
    public static String getIpAddr(HttpServletRequest request) {
        String ipAddress = null;
        try {
            ipAddress = request.getHeader("x-forwarded-for");
            if (ipAddress == null || ipAddress.length() == 0 || "unknown".equalsIgnoreCase(ipAddress)) {
                ipAddress = request.getHeader("Proxy-Client-IP");
            }
            if (ipAddress == null || ipAddress.length() == 0 || "unknown".equalsIgnoreCase(ipAddress)) {
                ipAddress = request.getHeader("WL-Proxy-Client-IP");
            }
            if (ipAddress == null || ipAddress.length() == 0 || "unknown".equalsIgnoreCase(ipAddress)) {
                ipAddress = request.getRemoteAddr();
                if (ipAddress.equals("127.0.0.1")) {
                    // 根据网卡取本机配置的IP
                    InetAddress inet = null;
                    try {
                        inet = InetAddress.getLocalHost();
                    } catch (UnknownHostException e) {
                        e.printStackTrace();
                    }
                    ipAddress = inet.getHostAddress();
                }
            }
            // 对于通过多个代理的情况，第一个IP为客户端真实IP,多个IP按照','分割
            if (ipAddress != null && ipAddress.length() > 15) {
                // "***.***.***.***".length()
                // = 15
                if (ipAddress.indexOf(",") > 0) {
                    ipAddress = ipAddress.substring(0, ipAddress.indexOf(","));
                }
            }
        } catch (Exception e) {
            ipAddress = "";
        }
        return ipAddress;
    }

    /**
     * MD5
     */
    public static String MD5(String data)  {
        try {
            java.security.MessageDigest md = MessageDigest.getInstance("MD5");
            byte[] array = md.digest(data.getBytes("UTF-8"));
            StringBuilder sb = new StringBuilder();
            for (byte item : array) {
                sb.append(Integer.toHexString((item & 0xFF) | 0x100).substring(1, 3));
            }
            return sb.toString().toUpperCase();
        } catch (Exception exception) {
        }
        return null;
    }

    /**
     * (并发有可能会重复)
     * 生成一个随机订单编码 ([prefix]-时间戳-3位随机数)
     * 例如：OR-3322113441-323
     */
    public static String generateRandomOrderCode(String prefix) {
        Random random = new Random();
        String randomNumber = String.format("%03d", random.nextInt(1000));
        String timestamp = LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyyMMddHHmmss"));
        return prefix + "-" + timestamp + "-" + randomNumber;
    }

    /**
     * (唯一UUID) 生成一个随机订单编码
     */
    public static String generateUniqueRandomOrderCode(String prefix) {
        String uuid = UUID.randomUUID().toString().replaceAll("-", "");
        return prefix + "-" + uuid.toUpperCase();
    }

    /**
     * 快速获得当前时间 (yyyy-MM-dd HH:mm:ss)
     */
    public static String getCurrentTime() {
        // 获取当前时间并格式化为 "yyyy-MM-DD HH:mm:ss" 的格式
        return DateUtil.format(new Date(), "yyyy-MM-dd HH:mm:ss");
    }

    /**
     * 生成新的文件名 (基于当前日期时间 及 后缀名)
     */
    public static String generateFilename(String suffix) {
        String timeStamp = new SimpleDateFormat("yyyyMMddHHmmss").format(new Date());
        // 检查suffix是否以点开头，如果没有，则添加一个点
        String fileSuffix = (suffix != null && !suffix.startsWith(".")) ? "." + suffix : suffix;
        String newFileName = timeStamp + fileSuffix;
        return newFileName;
    }

    /**
     * 根据远程地址，获得文件大小
     */
    public static Long getRemoteFileSize(String remote_url) {
        try {
            URL url = new URL(remote_url);
            // 获得文件元数据
            HttpURLConnection connection = (HttpURLConnection) url.openConnection();
            // 设置请求方法为HEAD，这样一般不会下载文件内容，只获取响应头
            connection.setRequestMethod("HEAD");
            // 连接到服务器
            connection.connect();
            // 获取响应头中的Content-Length属性，即文件的大小
            int contentLength = connection.getContentLength();
            return (long) contentLength;
        } catch (MalformedURLException e) {
            throw new CustException(e.getMessage());
        } catch (ProtocolException e) {
            throw new RuntimeException(e);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * 获得提交代码的版本号
     */
    public String getPushVersion() {
        String activeProfile = env.getActiveProfiles()[0];
        if ("local".equals(activeProfile)) {
            // 本地目录
            String path = FileUtil.getParent(
                    this.getClass().getProtectionDomain().getCodeSource().getLocation().getFile(), 2) + "./version.txt";
            return FileUtil.readUtf8String(path).trim();
        } else {
            // 自动部署的目录
            String versionFile = "/app/build/version.txt"; // 上一级目录
            return FileUtil.exist(versionFile)
                    ? FileUtil.readUtf8String(versionFile).trim()
                    : "0.0.0";
        }
    }

}
