package org.example.Utils;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;


import jakarta.servlet.ServletContext;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;

import java.io.File;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
 * 站点帮助类（对应原C# SiteUtil）
 * 功能：检测Web应用是否包含指定虚拟目录（带缓存）
 * 创建者：zyw
 * 创建日期：2016-09-12 13:40:19
 */
public class SiteUtil {
    private static final Logger log = LoggerFactory.getLogger(SiteUtil.class);

    // 缓存存储虚拟目录检测结果（线程安全的ConcurrentHashMap替代C# Dictionary）
    private static final Map<String, CacheEntry> CACHE = new ConcurrentHashMap<>();
    // 同步锁对象（替代C#的lock）
    private static final Object LOCK_OBJECT = new Object();
    // 缓存过期时间（毫秒），默认30秒
    private static int cacheTimeoutMs = 30000;

    // 私有化构造方法，确保工具类不可实例化
    private SiteUtil() {
    }

    /**
     * 准确检测当前Web应用是否包含指定虚拟目录（带缓存）
     *
     * @param virtualDirectoryName 要检测的虚拟目录名称
     * @return 如果存在返回true，否则返回false
     */
    public static boolean containsVirtualDirectory(String virtualDirectoryName) {
        // 空值/空白判断
        if (virtualDirectoryName == null || virtualDirectoryName.trim().isEmpty()) {
            return false;
        }

        // 标准化虚拟目录名称作为缓存键
        String normalizedKey = normalizeVirtualDirectoryName(virtualDirectoryName);

        synchronized (LOCK_OBJECT) {
            // 检查缓存
            CacheEntry cachedEntry = CACHE.get(normalizedKey);
            if (cachedEntry != null) {
                if (!cachedEntry.isExpired()) {
                    // 缓存未过期，直接返回结果
                    return cachedEntry.exists;
                } else {
                    // 缓存已过期，移除缓存
                    CACHE.remove(normalizedKey);
                }
            }

            // 缓存未命中或已过期，执行实际检测
            boolean result = containsVirtualDir(virtualDirectoryName);

            // 存储到缓存
            CACHE.put(normalizedKey, new CacheEntry(
                    result,
                    System.currentTimeMillis(),
                    cacheTimeoutMs
            ));

            return result;
        }
    }

    /**
     * 最终的检测方法 - 结合多种验证手段
     *
     * @param virtualDirectoryName 虚拟目录名称
     * @return 是否存在该虚拟目录
     */
    public static boolean containsVirtualDir(String virtualDirectoryName) {
        // 获取当前请求上下文（替代C#的HttpContext.Current）
        HttpServletRequest request = RequestContextHolder.getRequest();
        HttpServletResponse response = RequestContextHolder.getResponse();
        if (request == null) {
            // System.out.println("错误: 不在Web应用上下文中，无法检测虚拟目录");
            return false;
        }

        // 空值/空白判断
        if (virtualDirectoryName == null || virtualDirectoryName.trim().isEmpty()) {
            return false;
        }

        // 清理虚拟目录名称（去除开头的/）
        String cleanVirtualDirName = virtualDirectoryName.trim().replaceFirst("^/+", "");

        try {
            ServletContext servletContext = request.getServletContext();

            // 尝试映射虚拟目录路径（替代C#的Server.MapPath）
            String virtualDirPath = "/" + cleanVirtualDirName;
            String mappedPath = servletContext.getRealPath(virtualDirPath);

            // 获取应用根目录
            String appRootPath = servletContext.getRealPath("/") + cleanVirtualDirName;

            // 关键判断逻辑（和原C#完全一致）：
            // 1. 映射路径不能为空
            // 2. 映射路径不能等于应用根目录（除非虚拟目录就是根目录）
            if (mappedPath == null || mappedPath.isEmpty()) {
                return false;
            }

            // 构建根目录文件对象（用于判断目录是否存在）
            File appRootFile = new File(appRootPath);

            // 核心判断：映射路径不等于应用根目录 或 应用根目录存在 或 虚拟目录名为空（根目录）
            return !(mappedPath.equalsIgnoreCase(appRootPath)
                    && !appRootFile.exists()
                    && !cleanVirtualDirName.isEmpty());

        } catch (Exception ex) {
            log.debug(String.valueOf("检测过程中发生异常: " + ex.getMessage()));
            return false;
        }
    }

    /**
     * 标准化虚拟目录名称作为缓存键
     *
     * @param virtualDirectoryName 原始虚拟目录名称
     * @return 标准化后的缓存键
     */
    private static String normalizeVirtualDirectoryName(String virtualDirectoryName) {
        if (virtualDirectoryName == null || virtualDirectoryName.trim().isEmpty()) {
            return "";
        }
        // 去除开头的/，并转为小写
        return virtualDirectoryName.trim().replaceFirst("^/+", "").toLowerCase();
    }

    /**
     * 缓存条目类（对应原C#的CacheEntry）
     */
    private static class CacheEntry {
        // 是否存在虚拟目录
        private boolean exists;
        // 缓存时间戳（毫秒）
        private long timestamp;
        // 过期时间（毫秒）
        private int timeoutMs;

        public CacheEntry(boolean exists, long timestamp, int timeoutMs) {
            this.exists = exists;
            this.timestamp = timestamp;
            this.timeoutMs = timeoutMs;
        }

        /**
         * 判断缓存是否过期
         *
         * @return 过期返回true，否则false
         */
        public boolean isExpired() {
            return (System.currentTimeMillis() - timestamp) > timeoutMs;
        }

        // getter
        public boolean isExists() {
            return exists;
        }
    }

    /**
     * 请求上下文持有器（用于获取当前HttpServletRequest）
     * 需结合Spring MVC等框架使用，若未使用框架可替换为自定义实现
     */
    public static class RequestContextHolder {
        // ThreadLocal存储当前请求（线程安全）
        private static final ThreadLocal<HttpServletRequest> REQUEST_HOLDER = new ThreadLocal<>();
        private static final ThreadLocal<HttpServletResponse> RESPONSE_HOLDER = new ThreadLocal<>();

        /**
         * 设置当前请求
         *
         * @param request HttpServletRequest
         */
        public static void setRequest(HttpServletRequest request) {
            REQUEST_HOLDER.set(request);
        }

        /**
         * 设置当前响应
         *
         * @param response HttpServletResponse
         */
        public static void setResponse(HttpServletResponse response) {
            RESPONSE_HOLDER.set(response);
        }

        /**
         * 获取当前请求
         *
         * @return 当前HttpServletRequest，无则返回null
         */
        public static HttpServletRequest getRequest() {
            return REQUEST_HOLDER.get();
        }

        /**
         * 获取当前响应
         *
         * @return 当前HttpServletResponse，无则返回null
         */
        public static HttpServletResponse getResponse() {
            return RESPONSE_HOLDER.get();
        }

        /**
         * 清除当前线程的上下文
         */
        public static void clear() {
            REQUEST_HOLDER.remove();
            RESPONSE_HOLDER.remove();
        }
    }

    // ------------------- 可选配置方法 -------------------

    /**
     * 设置缓存过期时间
     *
     * @param timeoutMs 过期时间（毫秒）
     */
    public static void setCacheTimeoutMs(int timeoutMs) {
        cacheTimeoutMs = timeoutMs;
    }
}