package com.lingniu.ingest.eventhistory;

import java.time.Instant;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.OffsetDateTime;
import java.time.ZoneId;

/**
 * 查询时间范围解析器。
 *
 * <p>HTTP 查询允许传日期、带时区时间或不带时区的本地时间：
 * 日期用于分区裁剪，不带时区的时间统一按 Asia/Shanghai 转成 UTC Instant。
 * 返回值同时包含 LocalDate 分区边界和精确到秒/毫秒的 eventTime 边界。
 */
final class QueryTimeRange {

    private static final ZoneId DEFAULT_ZONE = ZoneId.of("Asia/Shanghai");

    private final LocalDate dateFrom;
    private final LocalDate dateTo;
    private final Instant eventTimeFrom;
    private final Instant eventTimeTo;

    private QueryTimeRange(LocalDate dateFrom, LocalDate dateTo, Instant eventTimeFrom, Instant eventTimeTo) {
        this.dateFrom = dateFrom;
        this.dateTo = dateTo;
        this.eventTimeFrom = eventTimeFrom;
        this.eventTimeTo = eventTimeTo;
    }

    static QueryTimeRange parse(String from, String to) {
        Boundary start = parseBoundary(from, false);
        Boundary end = parseBoundary(to, true);
        if (end.instant() != null && start.instant() != null && end.instant().isBefore(start.instant())) {
            throw new IllegalArgumentException("dateTo must not be before dateFrom");
        }
        if (end.date().isBefore(start.date())) {
            throw new IllegalArgumentException("dateTo must not be before dateFrom");
        }
        return new QueryTimeRange(start.date(), end.date(), start.instant(), end.instant());
    }

    LocalDate dateFrom() {
        return dateFrom;
    }

    LocalDate dateTo() {
        return dateTo;
    }

    Instant eventTimeFrom() {
        return eventTimeFrom;
    }

    Instant eventTimeTo() {
        return eventTimeTo;
    }

    private static Boundary parseBoundary(String raw, boolean endOfRange) {
        if (raw == null || raw.isBlank()) {
            throw new IllegalArgumentException("date range must not be blank");
        }
        String value = raw.trim();
        if (value.length() == 10) {
            // 纯日期查询覆盖东八区自然日；结束日期取当天最后一毫秒，兼容 dateTo=2026-06-23。
            LocalDate date = LocalDate.parse(value);
            Instant instant = endOfRange
                    ? date.plusDays(1).atStartOfDay(DEFAULT_ZONE).toInstant().minusMillis(1)
                    : date.atStartOfDay(DEFAULT_ZONE).toInstant();
            return new Boundary(date, instant);
        }
        try {
            // 带 Z 或 +08:00 的时间按调用方显式时区解析。
            Instant instant = OffsetDateTime.parse(value).toInstant();
            return new Boundary(LocalDate.ofInstant(instant, DEFAULT_ZONE), instant);
        } catch (RuntimeException ignored) {
            // 不带时区的前端输入按东八区解释，接口返回的数据时间本身仍保持原始 UTC 字符串。
            LocalDateTime local = LocalDateTime.parse(value);
            Instant instant = local.atZone(DEFAULT_ZONE).toInstant();
            return new Boundary(local.toLocalDate(), instant);
        }
    }

    private record Boundary(LocalDate date, Instant instant) {
    }
}
