package gc.mda.signal_batch.global.util;

import java.time.LocalDateTime;
import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter;
import java.time.format.DateTimeParseException;
import java.util.Arrays;
import java.util.List;

/**
 * 다양한 날짜/시간 형식을 파싱하는 유틸리티 클래스
 *
 * <p>지원 형식:</p>
 * <ul>
 *   <li>ISO 8601 (T 포함): 2026-01-20T10:00:00</li>
 *   <li>ISO 8601 with timezone: 2026-01-20T10:00:00Z, 2026-01-20T10:00:00+09:00</li>
 *   <li>표준 형식 (공백 구분): 2026-01-20 10:00:00</li>
 *   <li>초 생략 형식: 2026-01-20T10:00, 2026-01-20 10:00</li>
 *   <li>압축 형식: 20260120100000 (YYYYMMDDHHMMSS)</li>
 *   <li>압축 형식 (초 생략): 202601201000 (YYYYMMDDHHMM)</li>
 * </ul>
 *
 * <p>사용 예:</p>
 * <pre>{@code
 * LocalDateTime dt1 = DateTimeParseUtil.parse("2026-01-20T10:00:00");
 * LocalDateTime dt2 = DateTimeParseUtil.parse("2026-01-20 10:00:00");
 * LocalDateTime dt3 = DateTimeParseUtil.parse("20260120100000");
 * }</pre>
 */
public class DateTimeParseUtil {

    /**
     * 지원하는 날짜/시간 형식 목록 (우선순위 순)
     */
    private static final List<DateTimeFormatter> FORMATTERS = Arrays.asList(
            // ISO 8601 with timezone (Z or offset)
            DateTimeFormatter.ISO_ZONED_DATE_TIME,
            DateTimeFormatter.ISO_OFFSET_DATE_TIME,
            // ISO 8601 standard
            DateTimeFormatter.ISO_LOCAL_DATE_TIME,
            // Standard format with space
            DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"),
            // Without seconds
            DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm"),
            DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm"),
            // Compact format (YYYYMMDDHHMMSS)
            DateTimeFormatter.ofPattern("yyyyMMddHHmmss"),
            // Compact format without seconds (YYYYMMDDHHMM)
            DateTimeFormatter.ofPattern("yyyyMMddHHmm")
    );

    /**
     * Timezone 포함 형식 판별용
     */
    private static final List<DateTimeFormatter> ZONED_FORMATTERS = Arrays.asList(
            DateTimeFormatter.ISO_ZONED_DATE_TIME,
            DateTimeFormatter.ISO_OFFSET_DATE_TIME
    );

    private DateTimeParseUtil() {
        // Utility class - prevent instantiation
    }

    /**
     * 다양한 형식의 날짜/시간 문자열을 LocalDateTime으로 파싱
     *
     * @param dateTimeString 파싱할 날짜/시간 문자열
     * @return 파싱된 LocalDateTime
     * @throws IllegalArgumentException 지원하지 않는 형식인 경우
     */
    public static LocalDateTime parse(String dateTimeString) {
        if (dateTimeString == null || dateTimeString.isBlank()) {
            throw new IllegalArgumentException("날짜/시간 문자열이 null이거나 비어있습니다.");
        }

        String trimmed = dateTimeString.trim();

        // Try zoned formatters first for Z or offset patterns
        if (trimmed.contains("Z") || trimmed.matches(".*[+-]\\d{2}:\\d{2}$")) {
            for (DateTimeFormatter formatter : ZONED_FORMATTERS) {
                try {
                    ZonedDateTime zdt = ZonedDateTime.parse(trimmed, formatter);
                    return zdt.toLocalDateTime();
                } catch (DateTimeParseException ignored) {
                    // Try next formatter
                }
            }
        }

        // Try other formatters
        for (DateTimeFormatter formatter : FORMATTERS) {
            if (ZONED_FORMATTERS.contains(formatter)) {
                continue; // Skip zoned formatters already tried
            }
            try {
                return LocalDateTime.parse(trimmed, formatter);
            } catch (DateTimeParseException ignored) {
                // Try next formatter
            }
        }

        throw new IllegalArgumentException(
                "지원하지 않는 날짜/시간 형식입니다: " + dateTimeString + "\n" +
                "지원 형식: ISO 8601 (2026-01-20T10:00:00, 2026-01-20T10:00:00Z), " +
                "표준 형식 (2026-01-20 10:00:00), 압축 형식 (20260120100000)"
        );
    }

    /**
     * 날짜/시간 문자열 파싱 시도 (실패 시 null 반환)
     *
     * @param dateTimeString 파싱할 날짜/시간 문자열
     * @return 파싱된 LocalDateTime 또는 null
     */
    public static LocalDateTime parseOrNull(String dateTimeString) {
        try {
            return parse(dateTimeString);
        } catch (IllegalArgumentException e) {
            return null;
        }
    }

    /**
     * 날짜/시간 문자열이 파싱 가능한지 확인
     *
     * @param dateTimeString 확인할 날짜/시간 문자열
     * @return 파싱 가능 여부
     */
    public static boolean isValid(String dateTimeString) {
        return parseOrNull(dateTimeString) != null;
    }

    /**
     * LocalDateTime을 ISO 8601 형식으로 포맷
     *
     * @param dateTime 포맷할 LocalDateTime
     * @return ISO 8601 형식 문자열 (예: 2026-01-20T10:00:00)
     */
    public static String formatIso(LocalDateTime dateTime) {
        if (dateTime == null) {
            return null;
        }
        return dateTime.format(DateTimeFormatter.ISO_LOCAL_DATE_TIME);
    }

    /**
     * LocalDateTime을 표준 형식으로 포맷
     *
     * @param dateTime 포맷할 LocalDateTime
     * @return 표준 형식 문자열 (예: 2026-01-20 10:00:00)
     */
    public static String formatStandard(LocalDateTime dateTime) {
        if (dateTime == null) {
            return null;
        }
        return dateTime.format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
    }

    /**
     * 지원 형식 설명 문자열 반환 (API 문서용)
     *
     * @return 지원 형식 설명
     */
    public static String getSupportedFormatsDescription() {
        return """
            지원 형식:
            • ISO 8601: 2026-01-20T10:00:00
            • ISO 8601 (UTC): 2026-01-20T10:00:00Z
            • ISO 8601 (Offset): 2026-01-20T10:00:00+09:00
            • 표준 형식: 2026-01-20 10:00:00
            • 초 생략: 2026-01-20T10:00, 2026-01-20 10:00
            • 압축 형식: 20260120100000 (YYYYMMDDHHMMSS)
            • 압축 형식 (초 생략): 202601201000 (YYYYMMDDHHMM)
            """;
    }
}
