package com.common.util;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.time.*;
import java.time.format.DateTimeFormatter;
import java.time.format.DateTimeFormatterBuilder;
import java.time.format.DateTimeParseException;
import java.time.temporal.ChronoField;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.regex.Pattern;

/**
 * 时间转换工具类 - 支持多种时间格式
 * 支持格式包括：
 * 1. 2025-11-01T15:23:41.188078+0800 (6位微秒，+0800时区)
 * 2. 2025-11-01T15:23:41.188+0800 (3位毫秒，+0800时区)
 * 3. 2025-11-01T15:23:41+0800 (无小数秒，+0800时区)
 * 4. 2025-11-01T15:23:41.188078+08:00 (6位微秒，带冒号时区)
 * 5. 2025-11-01T15:23:41.188Z (UTC时间，Z表示)
 * 6. yyyy-MM-dd'T'HH:mm:ss.SSS'Z' (您原始格式)
 * 7. 多种其他常见格式
 */
public class TimeConversionUtils {

    // 缓存SimpleDateFormat对象（非线程安全，使用ThreadLocal）
    private static final ConcurrentHashMap<String, ThreadLocal<SimpleDateFormat>> SDF_CACHE = new ConcurrentHashMap<>();

    // 缓存DateTimeFormatter对象（线程安全）
    private static final ConcurrentHashMap<String, DateTimeFormatter> DTF_CACHE = new ConcurrentHashMap<>();

    // 预定义的常用格式列表
    private static final List<DateTimeFormatter> PREDEFINED_FORMATTERS = new ArrayList<>();

    static {
        // 初始化预定义格式
        initPredefinedFormatters();
    }

    /**
     * 初始化预定义的多种时间格式
     */
    private static void initPredefinedFormatters() {
        // 1. 6位微秒，+0800时区格式
        PREDEFINED_FORMATTERS.add(new DateTimeFormatterBuilder()
                .appendPattern("yyyy-MM-dd'T'HH:mm:ss")
                .appendFraction(ChronoField.MICRO_OF_SECOND, 0, 6, true)
                .appendPattern("xx")
                .toFormatter());

        // 2. 3位毫秒，+0800时区格式
        PREDEFINED_FORMATTERS.add(DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss.SSSxx"));

        // 3. 无小数秒，+0800时区格式
        PREDEFINED_FORMATTERS.add(DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ssxx"));

        // 4. 6位微秒，带冒号时区格式
        PREDEFINED_FORMATTERS.add(new DateTimeFormatterBuilder()
                .appendPattern("yyyy-MM-dd'T'HH:mm:ss")
                .appendFraction(ChronoField.MICRO_OF_SECOND, 0, 6, true)
                .appendPattern("xxx")
                .toFormatter());

        // 5. 3位毫秒，带冒号时区格式
        PREDEFINED_FORMATTERS.add(DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss.SSSxxx"));

        // 6. 无小数秒，带冒号时区格式
        PREDEFINED_FORMATTERS.add(DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ssxxx"));

        // 7. UTC时间，Z表示，6位微秒
        PREDEFINED_FORMATTERS.add(new DateTimeFormatterBuilder()
                .appendPattern("yyyy-MM-dd'T'HH:mm:ss")
                .appendFraction(ChronoField.MICRO_OF_SECOND, 0, 6, true)
                .appendPattern("'Z'")
                .toFormatter());

        // 8. UTC时间，Z表示，3位毫秒
        PREDEFINED_FORMATTERS.add(DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'"));

        // 9. 无时区信息，6位微秒
        PREDEFINED_FORMATTERS.add(new DateTimeFormatterBuilder()
                .appendPattern("yyyy-MM-dd'T'HH:mm:ss")
                .appendFraction(ChronoField.MICRO_OF_SECOND, 0, 6, true)
                .toFormatter());

        // 10. 无时区信息，3位毫秒
        PREDEFINED_FORMATTERS.add(DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss.SSS"));

        // 11. 标准ISO格式
        PREDEFINED_FORMATTERS.add(DateTimeFormatter.ISO_OFFSET_DATE_TIME);
        PREDEFINED_FORMATTERS.add(DateTimeFormatter.ISO_ZONED_DATE_TIME);
        PREDEFINED_FORMATTERS.add(DateTimeFormatter.ISO_LOCAL_DATE_TIME);

        // 12. 其他常见格式
        PREDEFINED_FORMATTERS.add(DateTimeFormatter.ofPattern("yyyy/MM/dd HH:mm:ss.SSS"));
        PREDEFINED_FORMATTERS.add(DateTimeFormatter.ofPattern("yyyy年MM月dd日 HH:mm:ss"));
        PREDEFINED_FORMATTERS.add(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
        PREDEFINED_FORMATTERS.add(DateTimeFormatter.ofPattern("dd/MM/yyyy HH:mm:ss"));
        PREDEFINED_FORMATTERS.add(DateTimeFormatter.ofPattern("MM/dd/yyyy HH:mm:ss"));
    }

    /**
     * 主转换方法 - 智能解析多种时间格式
     *
     * @param dateString 时间字符串
     * @param timezone 时区（CST/UTC），当时间字符串中不包含时区信息时使用
     * @return 毫秒级时间戳
     * @throws ParseException 解析失败时抛出异常
     */
    public static long convertToMillis(String dateString, String timezone) throws ParseException {
        // 1. 首先尝试使用预定义的格式智能解析
        try {
            return smartParseToMillis(dateString, timezone);
        } catch (Exception e1) {
            // 2. 如果智能解析失败，尝试正则表达式匹配
            try {
                return parseWithRegex(dateString, timezone);
            } catch (Exception e2) {
                // 3. 如果都失败，尝试SimpleDateFormat的通用解析
                return parseWithSimpleDateFormat(dateString, timezone);
            }
        }
    }

    /**
     * 智能解析 - 尝试所有预定义格式
     */
    private static long smartParseToMillis(String dateString, String timezone) throws ParseException {
        // 移除空格和非法字符
        dateString = cleanDateString(dateString);

        // 尝试所有预定义格式
        for (DateTimeFormatter formatter : PREDEFINED_FORMATTERS) {
            try {
                return parseWithFormatter(dateString, formatter, timezone);
            } catch (DateTimeParseException e) {
                // 尝试下一个格式
                continue;
            }
        }

        throw new ParseException("无法解析时间字符串: " + dateString, 0);
    }

    /**
     * 使用指定的DateTimeFormatter解析
     */
    private static long parseWithFormatter(String dateString, DateTimeFormatter formatter, String timezone)
            throws DateTimeParseException {

        try {
            // 尝试解析为OffsetDateTime（包含时区）
            OffsetDateTime odt = OffsetDateTime.parse(dateString, formatter);
            return odt.toInstant().toEpochMilli();
        } catch (DateTimeParseException e1) {
            try {
                // 尝试解析为ZonedDateTime
                ZonedDateTime zdt = ZonedDateTime.parse(dateString, formatter);
                return zdt.toInstant().toEpochMilli();
            } catch (DateTimeParseException e2) {
                try {
                    // 尝试解析为LocalDateTime，然后附加时区
                    LocalDateTime ldt = LocalDateTime.parse(dateString, formatter);
                    ZonedDateTime zdt = ldt.atZone(getZoneId(timezone));
                    return zdt.toInstant().toEpochMilli();
                } catch (DateTimeParseException e3) {
                    throw e1; // 抛出原始异常
                }
            }
        }
    }

    /**
     * 使用正则表达式解析（处理特殊格式）
     */
    private static long parseWithRegex(String dateString, String timezone) throws ParseException {
        // 定义常见时间格式的正则表达式
        Map<Pattern, String> regexPatterns = new LinkedHashMap<>();

        // 匹配 2025-11-01T15:23:41.188078+0800 格式
        regexPatterns.put(
                Pattern.compile("^(\\d{4}-\\d{2}-\\d{2})T(\\d{2}:\\d{2}:\\d{2})\\.(\\d{1,6})([+-]\\d{4})$"),
                "MICROSECONDS_WITH_OFFSET"
        );

        // 匹配 2025-11-01T15:23:41.188078+08:00 格式
        regexPatterns.put(
                Pattern.compile("^(\\d{4}-\\d{2}-\\d{2})T(\\d{2}:\\d{2}:\\d{2})\\.(\\d{1,6})([+-]\\d{2}:\\d{2})$"),
                "MICROSECONDS_WITH_COLON_OFFSET"
        );

        // 尝试匹配并解析
        for (Map.Entry<Pattern, String> entry : regexPatterns.entrySet()) {
            java.util.regex.Matcher matcher = entry.getKey().matcher(dateString);
            if (matcher.matches()) {
                return parseWithRegexMatcher(matcher, entry.getValue(), timezone);
            }
        }

        throw new ParseException("正则表达式无法匹配时间字符串: " + dateString, 0);
    }

    /**
     * 解析正则表达式匹配的结果
     */
    private static long parseWithRegexMatcher(java.util.regex.Matcher matcher, String patternType, String timezone)
            throws ParseException {

        String datePart = matcher.group(1);
        String timePart = matcher.group(2);
        String fractionPart = matcher.group(3);
        String offsetPart = matcher.group(4);

        // 处理微秒/毫秒部分
        int nanoseconds;
        if (fractionPart.length() <= 3) {
            // 毫秒
            nanoseconds = Integer.parseInt(fractionPart) * 1_000_000;
        } else {
            // 微秒或纳秒
            if (fractionPart.length() > 6) {
                fractionPart = fractionPart.substring(0, 6); // 最多保留6位
            }
            while (fractionPart.length() < 6) {
                fractionPart = fractionPart + "0";
            }
            nanoseconds = Integer.parseInt(fractionPart) * 1000; // 微秒转纳秒
        }

        try {
            // 构建LocalDateTime
            LocalDateTime ldt = LocalDateTime.parse(datePart + "T" + timePart);

            // 处理时区
            ZonedDateTime zdt;
            if (offsetPart != null && !offsetPart.isEmpty()) {
                // 有时区偏移
                String offsetStr = offsetPart.replace(":", "");
                if (offsetStr.length() == 5) { // +0800 或 -0500
                    int hours = Integer.parseInt(offsetStr.substring(0, 3));
                    int minutes = Integer.parseInt(offsetStr.substring(3));
                    ZoneOffset offset = ZoneOffset.ofHoursMinutes(hours, minutes);
                    zdt = ldt.atZone(offset);
                } else if (offsetStr.equalsIgnoreCase("Z")) {
                    zdt = ldt.atZone(ZoneOffset.UTC);
                } else {
                    // 默认使用提供的时区
                    zdt = ldt.atZone(getZoneId(timezone));
                }
            } else {
                // 无时区信息，使用提供的时区
                zdt = ldt.atZone(getZoneId(timezone));
            }

            // 添加纳秒部分
            zdt = zdt.withNano(nanoseconds);

            return zdt.toInstant().toEpochMilli();

        } catch (Exception e) {
            throw new ParseException("正则解析失败: " + e.getMessage(), 0);
        }
    }

    /**
     * 使用SimpleDateFormat解析（兼容Java 7）
     */
    private static long parseWithSimpleDateFormat(String dateString, String timezone) throws ParseException {
        // 清理字符串
        dateString = cleanDateString(dateString);

        // 准备多种格式尝试
        String[] patterns = {
                "yyyy-MM-dd'T'HH:mm:ss.SSSXXX",
                "yyyy-MM-dd'T'HH:mm:ssXXX",
                "yyyy-MM-dd HH:mm:ss.SSS",
                "yyyy-MM-dd HH:mm:ss",
                "yyyy/MM/dd HH:mm:ss",
                "dd/MM/yyyy HH:mm:ss",
                "MM/dd/yyyy HH:mm:ss"
        };

        for (String pattern : patterns) {
            try {
                SimpleDateFormat sdf = getCachedSimpleDateFormat(pattern, timezone);
                Date date = sdf.parse(dateString);
                return date.getTime();
            } catch (ParseException e) {
                continue;
            }
        }

        throw new ParseException("无法解析时间字符串: " + dateString, 0);
    }

    /**
     * 清理时间字符串
     */
    private static String cleanDateString(String dateString) {
        if (dateString == null) {
            return "";
        }

        // 移除前后空格
        String cleaned = dateString.trim();

        // 替换中文括号等
        cleaned = cleaned.replace("（", "(").replace("）", ")");

        // 处理常见的错误格式
        cleaned = cleaned.replace("T ", "T"); // 移除T后面的空格

        return cleaned;
    }

    /**
     * 获取缓存的SimpleDateFormat
     */
    private static SimpleDateFormat getCachedSimpleDateFormat(String pattern, String timezone) {
        String key = pattern + "_" + timezone;

        ThreadLocal<SimpleDateFormat> threadLocalSdf = SDF_CACHE.computeIfAbsent(key, k ->
                ThreadLocal.withInitial(() -> {
                    SimpleDateFormat sdf = new SimpleDateFormat(pattern);
                    sdf.setTimeZone(getTimeZone(timezone));
                    return sdf;
                })
        );

        return threadLocalSdf.get();
    }

    /**
     * 获取缓存的DateTimeFormatter
     */
    private static DateTimeFormatter getCachedDateTimeFormatter(String pattern) {
        return DTF_CACHE.computeIfAbsent(pattern, DateTimeFormatter::ofPattern);
    }

    /**
     * 获取ZoneId
     */
    private static ZoneId getZoneId(String timezone) {
        if (timezone == null) {
            return ZoneId.systemDefault();
        }

        switch (timezone.toUpperCase()) {
            case "CST":
                return ZoneId.of("Asia/Shanghai");
            case "UTC":
                return ZoneId.of("UTC");
            case "GMT":
                return ZoneId.of("GMT");
            case "EST":
                return ZoneId.of("America/New_York");
            case "PST":
                return ZoneId.of("America/Los_Angeles");
            default:
                try {
                    return ZoneId.of(timezone);
                } catch (Exception e) {
                    return ZoneId.systemDefault();
                }
        }
    }

    /**
     * 获取TimeZone
     */
    private static TimeZone getTimeZone(String timezone) {
        if (timezone == null) {
            return TimeZone.getDefault();
        }

        switch (timezone.toUpperCase()) {
            case "CST":
                return TimeZone.getTimeZone("Asia/Shanghai");
            case "UTC":
                return TimeZone.getTimeZone("UTC");
            case "GMT":
                return TimeZone.getTimeZone("GMT");
            case "EST":
                return TimeZone.getTimeZone("America/New_York");
            case "PST":
                return TimeZone.getTimeZone("America/Los_Angeles");
            default:
                TimeZone tz = TimeZone.getTimeZone(timezone);
                if ("GMT".equals(tz.getID()) && !"GMT".equalsIgnoreCase(timezone)) {
                    return TimeZone.getDefault();
                }
                return tz;
        }
    }

    /**
     * 检测Java版本是否支持java.time
     */
    public static boolean isJava8OrHigher() {
        try {
            Class.forName("java.time.LocalDateTime");
            return true;
        } catch (ClassNotFoundException e) {
            return false;
        }
    }

    /**
     * 根据Action JSON结构调用
     * 保持与原接口的兼容性
     */
    public static long processTimeConversion(String dateString, ActionParam param) throws Exception {
        if (param == null) {
            throw new IllegalArgumentException("ActionParam不能为空");
        }

        return convertToMillis(dateString, param.timezone);
    }

    /**
     * 添加自定义格式到预定义列表中
     */
    public static void addCustomFormatter(String pattern) {
        try {
            DateTimeFormatter formatter = DateTimeFormatter.ofPattern(pattern);
            PREDEFINED_FORMATTERS.add(0, formatter); // 添加到开头，优先尝试
        } catch (Exception e) {
            throw new IllegalArgumentException("无效的时间格式模式: " + pattern, e);
        }
    }

    /**
     * 添加自定义格式到预定义列表中（带优先级别）
     */
    public static void addCustomFormatter(String pattern, int priority) {
        try {
            DateTimeFormatter formatter = DateTimeFormatter.ofPattern(pattern);
            if (priority < 0) {
                PREDEFINED_FORMATTERS.add(formatter);
            } else {
                PREDEFINED_FORMATTERS.add(Math.min(priority, PREDEFINED_FORMATTERS.size()), formatter);
            }
        } catch (Exception e) {
            throw new IllegalArgumentException("无效的时间格式模式: " + pattern, e);
        }
    }

    /**
     * 获取支持的所有格式
     */
    public static List<String> getSupportedFormats() {
        List<String> formats = new ArrayList<>();
        for (DateTimeFormatter formatter : PREDEFINED_FORMATTERS) {
            formats.add(formatter.toString());
        }
        return formats;
    }

    // 模拟Action JSON结构的类
    public static class ActionParam {
        public String javaDateFormat;
        public String goDateFormat;
        public String timezone;

        public ActionParam() {}

        public ActionParam(String javaDateFormat, String timezone) {
            this.javaDateFormat = javaDateFormat;
            this.timezone = timezone;
        }
    }

    /**
     * 测试方法
     */
    public static void main(String[] args) {
        // 测试各种时间格式
        List<TestData> testCases = new ArrayList<>();

        // 添加测试用例
        testCases.add(new TestData("2025-11-01T15:23:41.188078+0800", "CST"));
        testCases.add(new TestData("2025-11-01T15:23:41.188+0800", "CST"));
        testCases.add(new TestData("2025-11-01T15:23:41+0800", "CST"));
        testCases.add(new TestData("2025-11-01T07:23:41.188078Z", "UTC"));
        testCases.add(new TestData("2025-11-01T15:23:41.188078+08:00", "CST"));
        testCases.add(new TestData("2025-11-01T15:23:41", "CST")); // 无时区
        testCases.add(new TestData("2025-11-01 15:23:41", "CST"));
        testCases.add(new TestData("2025/11/01 15:23:41.123", "CST"));
        testCases.add(new TestData("2025-11-01T15:23:41.123456", "UTC"));
        testCases.add(new TestData("2025年11月01日 15:23:41", "CST"));
        testCases.add(new TestData("01/11/2025 15:23:41", "CST"));
        testCases.add(new TestData("11/01/2025 15:23:41", "CST"));

        System.out.println("=== 时间格式转换测试 ===\n");

        for (TestData test : testCases) {
            try {
                long timestamp = convertToMillis(test.dateString, test.timezone);
                System.out.println(String.format("✓ 成功: %-40s | 时区: %-5s | 时间戳: %d",
                        test.dateString, test.timezone, timestamp));
            } catch (Exception e) {
                System.out.println(String.format("✗ 失败: %-40s | 时区: %-5s | 错误: %s",
                        test.dateString, test.timezone, e.getMessage()));
            }
        }

        // 测试Action JSON参数
        System.out.println("\n=== Action JSON参数测试 ===");
        try {
            ActionParam param = new ActionParam("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'", "CST");
            long timestamp = processTimeConversion("2025-11-01T15:23:41.188078+0800", param);
            System.out.println("Action JSON转换结果: " + timestamp);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    static class TestData {
        String dateString;
        String timezone;

        TestData(String dateString, String timezone) {
            this.dateString = dateString;
            this.timezone = timezone;
        }
    }
}