package com.ruoyi.framework.config;

import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.DeserializationContext;
import com.fasterxml.jackson.databind.JsonDeserializer;
import com.fasterxml.jackson.databind.module.SimpleModule;
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
import com.ruoyi.common.utils.StringUtils;
import org.springframework.boot.autoconfigure.jackson.Jackson2ObjectMapperBuilderCustomizer;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.convert.converter.Converter;

import java.io.IOException;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Date;

@Configuration
public class LocalDateTimeSerializerConfig {
    private static final String DATE_TIME_PATTERN = "yyyy-MM-dd HH:mm:ss";
    private static final String DATE_PATTERN = "yyyy-MM-dd";
    private static final DateTimeFormatter[] DATE_FORMATS = new DateTimeFormatter[]{
            DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss.SSSX"),
            DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss"),
            DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"),
            DateTimeFormatter.ofPattern("yyyy-MM-dd")
    };
    private static final String[] DATE_FORMATS2 = new String[]{
            "yyyy-MM-dd'T'HH:mm:ss.SSSX", // ISO 8601
            "yyyy-MM-dd'T'HH:mm:ss",
            "yyyy-MM-dd HH:mm:ss",
            "yyyy-MM-dd"
    };

    /**
     * string转localdate
     */
    @Bean
    public Converter<String, LocalDate> localDateConverter() {
        return new Converter<String, LocalDate>() {
            @Override
            public LocalDate convert(String source) {
                if (source.trim().length() == 0) {
                    return null;
                }
                try {
                    return LocalDate.parse(source);
                } catch (Exception e) {
                    return LocalDate.parse(source, DateTimeFormatter.ofPattern(DATE_PATTERN));
                }
            }
        };
    }


    //@Bean
    //public Jackson2ObjectMapperBuilderCustomizer jsonCustomizer2() {
    //    DateTimeFormatter formatter = DateTimeFormatter.ofPattern("[yyyy-MM-dd'T'HH:mm:ss][yyyy-MM-dd'T'HH:mm:ss.SSSX][yyyy-MM-dd HH:mm:ss][yyyy-MM-dd]")
    //            .withResolverStyle(ResolverStyle.STRICT);
    //
    //    JavaTimeModule module = new JavaTimeModule();
    //    LocalDateTimeDeserializer localDateTimeDeserializer = new LocalDateTimeDeserializer(formatter);
    //    module.addDeserializer(LocalDateTime.class, localDateTimeDeserializer);
    //
    //    return builder -> {
    //        builder.modules(module);
    //    };
    //}

    /**
     * string转localdatetime
     */
    @Bean
    public Converter<String, LocalDateTime> localDateTimeConverter() {
        return new Converter<String, LocalDateTime>() {
            @Override
            public LocalDateTime convert(String source) {
                if (source.trim().length() == 0) {
                    return null;
                }
                // 先尝试ISO格式: 2019-07-15T16:00:00
                try {
                    return LocalDateTime.parse(source);
                } catch (Exception e) {
                    return LocalDateTime.parse(source, DateTimeFormatter.ofPattern(DATE_TIME_PATTERN));
                }
            }
        };
    }

    /**
     * 统一配置
     */

    @Bean
    public Jackson2ObjectMapperBuilderCustomizer jsonCustomizer() {
        return builder -> {
            SimpleModule module = new SimpleModule();
            module.addDeserializer(Date.class, new CustomDateDeserializer());
            module.addDeserializer(LocalDate.class, new CustomLocalDateDeserializer());
            module.addDeserializer(LocalDateTime.class, new CustomLocalDateTimeDeserializer());

            builder.modules(module, new JavaTimeModule());
        };
    }

    class CustomLocalDateTimeDeserializer extends JsonDeserializer<LocalDateTime> {


        @Override
        public LocalDateTime deserialize(JsonParser jsonParser, DeserializationContext context) throws IOException {
            String date = jsonParser.getText();
            for (DateTimeFormatter formatter : DATE_FORMATS) {
                try {
                    return LocalDateTime.parse(date, formatter);
                } catch (Exception e) {
                    // Continue to next format
                }
            }
            throw new JsonProcessingException("Unparseable date: \"" + date + "\"") {
            };
        }
    }


    class CustomLocalDateDeserializer extends JsonDeserializer<LocalDate> {


        @Override
        public LocalDate deserialize(JsonParser jsonParser, DeserializationContext context) throws IOException {
            String date = jsonParser.getText();
            for (DateTimeFormatter formatter : DATE_FORMATS) {
                try {
                    return LocalDate.parse(date, formatter);
                } catch (Exception e) {
                    // Continue to next format
                }
            }
            throw new JsonProcessingException("Unparseable date: \"" + date + "\"") {
            };
        }
    }


    class CustomDateDeserializer extends JsonDeserializer<Date> {
        @Override
        public Date deserialize(JsonParser jsonParser, DeserializationContext context) throws IOException {
            String date = jsonParser.getText();
            if (StringUtils.isNotBlank(date)) {
                for (String format : DATE_FORMATS2) {
                    try {
                        return new SimpleDateFormat(format).parse(date);
                    } catch (ParseException e) {
                        // Continue to next format
                    }
                }
                throw new JsonProcessingException("Unparseable date: \"" + date + "\"") {
                };
            }
            return null;
            
        }
    }

}
