// tests/suite/test_time.el — comprehensive tests for runtime/time.el
//
// Covers time_now, now_millis, unix_timestamp, now_ns, time_format, time_to_parts,
// time_add, time_diff, duration helpers, and uuid_new.

// ── time_now / now_millis / unix_timestamp_ms ─────────────────────────────────

fn test_time_now_basic(_: String) -> String {
    let t: Int = time_now()
    // Milliseconds since epoch: must be well past year 2020 (1577836800000)
    assert_true(t > 1577836800000, "time_now is past 2020-01-01")
    // Must be before year 2100 (4102444800000)
    assert_true(t < 4102444800000, "time_now is before 2100-01-01")
    return ""
}

fn test_now_millis_basic(_: String) -> String {
    let t: Int = now_millis()
    assert_true(t > 1577836800000, "now_millis is past 2020-01-01")
    assert_true(t < 4102444800000, "now_millis is before 2100-01-01")
    return ""
}

fn test_unix_timestamp_ms_basic(_: String) -> String {
    let t: Int = unix_timestamp_ms()
    assert_true(t > 1577836800000, "unix_timestamp_ms is past 2020-01-01")
    assert_true(t < 4102444800000, "unix_timestamp_ms is before 2100-01-01")
    return ""
}

fn test_time_now_ms_alias(_: String) -> String {
    let t: Int = time_now_ms()
    assert_true(t > 1577836800000, "time_now_ms is past 2020-01-01")
    assert_true(t < 4102444800000, "time_now_ms is before 2100-01-01")
    return ""
}

// ── monotonicity ──────────────────────────────────────────────────────────────

fn test_time_monotonic_now_millis(_: String) -> String {
    let t1: Int = now_millis()
    let t2: Int = now_millis()
    assert_true(t2 >= t1, "second call >= first call (monotonic)")
    return ""
}

fn test_time_monotonic_time_now(_: String) -> String {
    let t1: Int = time_now()
    let t2: Int = time_now()
    assert_true(t2 >= t1, "time_now is monotonic across calls")
    return ""
}

fn test_time_monotonic_now_ns(_: String) -> String {
    let t1: Int = now_ns()
    let t2: Int = now_ns()
    assert_true(t2 >= t1, "now_ns is monotonic across calls")
    // ns should be much larger than ms (9 digits difference)
    assert_true(t1 > 1000000000000000000, "now_ns is in nanosecond scale")
    return ""
}

// ── unix_timestamp (seconds) ─────────────────────────────────────────────────

fn test_unix_timestamp_basic(_: String) -> String {
    let secs: Int = unix_timestamp()
    // Must be past 2020-01-01 in seconds (1577836800)
    assert_true(secs > 1577836800, "unix_timestamp is past 2020-01-01")
    // Must be before 2100-01-01 in seconds (4102444800)
    assert_true(secs < 4102444800, "unix_timestamp is before 2100-01-01")
    // seconds are about 1000x smaller than millis
    let ms: Int = time_now()
    assert_true(ms > secs, "milliseconds > seconds")
    return ""
}

// ── time_to_parts ─────────────────────────────────────────────────────────────

fn test_time_to_parts_basic(_: String) -> String {
    // Known timestamp: 2024-01-15 12:30:45.123 UTC
    // 2024-01-15 00:00:00 UTC = epoch + (54 * 365 + 14 leaps) days approximately
    // Use a precisely known value: 2024-01-15T12:30:45.123Z
    // epoch_ms = 1705320645123
    let ts: Int = 1705320645123
    let parts: String = time_to_parts(ts)
    assert_eq(json_get(parts, "year"), "2024", "year is 2024")
    assert_eq(json_get(parts, "month"), "1", "month is 1 (January)")
    assert_eq(json_get(parts, "day"), "15", "day is 15")
    assert_eq(json_get(parts, "hour"), "12", "hour is 12")
    assert_eq(json_get(parts, "minute"), "30", "minute is 30")
    assert_eq(json_get(parts, "second"), "45", "second is 45")
    assert_eq(json_get(parts, "ms"), "123", "milliseconds is 123")
    return ""
}

fn test_time_to_parts_epoch(_: String) -> String {
    // Unix epoch: 1970-01-01T00:00:00.000Z = timestamp 0
    let parts: String = time_to_parts(0)
    assert_eq(json_get(parts, "year"), "1970", "epoch year is 1970")
    assert_eq(json_get(parts, "month"), "1", "epoch month is 1")
    assert_eq(json_get(parts, "day"), "1", "epoch day is 1")
    assert_eq(json_get(parts, "hour"), "0", "epoch hour is 0")
    assert_eq(json_get(parts, "minute"), "0", "epoch minute is 0")
    assert_eq(json_get(parts, "second"), "0", "epoch second is 0")
    return ""
}

fn test_time_to_parts_current(_: String) -> String {
    let ts: Int = time_now()
    let parts: String = time_to_parts(ts)
    let year: Int = str_to_int(json_get(parts, "year"))
    let month: Int = str_to_int(json_get(parts, "month"))
    let day: Int = str_to_int(json_get(parts, "day"))
    let hour: Int = str_to_int(json_get(parts, "hour"))
    let minute: Int = str_to_int(json_get(parts, "minute"))
    let second: Int = str_to_int(json_get(parts, "second"))
    assert_true(year >= 2024, "current year >= 2024")
    assert_true(year < 2100, "current year < 2100")
    assert_true(month >= 1, "month >= 1")
    assert_true(month <= 12, "month <= 12")
    assert_true(day >= 1, "day >= 1")
    assert_true(day <= 31, "day <= 31")
    assert_true(hour >= 0, "hour >= 0")
    assert_true(hour <= 23, "hour <= 23")
    assert_true(minute >= 0, "minute >= 0")
    assert_true(minute <= 59, "minute <= 59")
    assert_true(second >= 0, "second >= 0")
    assert_true(second <= 59, "second <= 59")
    return ""
}

// ── time_format ───────────────────────────────────────────────────────────────

fn test_time_format_iso(_: String) -> String {
    let ts: Int = 1705320645123
    let iso: String = time_format(ts, "ISO")
    assert_starts_with(iso, "2024-01-15", "ISO format starts with correct date")
    assert_contains(iso, "T12:30:45", "ISO format has correct time")
    assert_ends_with(iso, "Z", "ISO format ends with Z")
    assert_contains(iso, "123", "ISO format includes milliseconds")
    return ""
}

fn test_time_format_empty(_: String) -> String {
    let ts: Int = 1705320645123
    let iso: String = time_format(ts, "")
    assert_starts_with(iso, "2024-01-15", "empty fmt gives ISO format")
    assert_ends_with(iso, "Z", "empty fmt gives ISO format ending in Z")
    return ""
}

fn test_time_format_strftime(_: String) -> String {
    let ts: Int = 1705320645123
    let formatted: String = time_format(ts, "%Y-%m-%d")
    assert_eq(formatted, "2024-01-15", "strftime %Y-%m-%d")
    let formatted2: String = time_format(ts, "%H:%M:%S")
    assert_eq(formatted2, "12:30:45", "strftime %H:%M:%S")
    return ""
}

// ── time_add ──────────────────────────────────────────────────────────────────

fn test_time_add_basic(_: String) -> String {
    let base: Int = 1000000000000
    assert_int_eq(time_add(base, 1000, "ms"), base + 1000, "add milliseconds")
    assert_int_eq(time_add(base, 1, "sec"), base + 1000, "add 1 second")
    assert_int_eq(time_add(base, 1, "min"), base + 60000, "add 1 minute")
    assert_int_eq(time_add(base, 1, "hour"), base + 3600000, "add 1 hour")
    assert_int_eq(time_add(base, 1, "day"), base + 86400000, "add 1 day")
    return ""
}

fn test_time_add_multiple(_: String) -> String {
    let base: Int = 1000000000000
    assert_int_eq(time_add(base, 60, "sec"), base + 60000, "add 60 seconds")
    assert_int_eq(time_add(base, 24, "hour"), base + 86400000, "add 24 hours = 1 day")
    assert_int_eq(time_add(base, 0, "sec"), base, "add 0 seconds")
    assert_int_eq(time_add(base, -1, "sec"), base - 1000, "add negative seconds")
    return ""
}

// ── time_diff ─────────────────────────────────────────────────────────────────

fn test_time_diff_basic(_: String) -> String {
    let t1: Int = 1000000000000
    let t2: Int = t1 + 5000
    assert_int_eq(time_diff(t1, t2, "ms"), 5000, "diff in ms")
    assert_int_eq(time_diff(t1, t2, "sec"), 5, "diff in seconds")
    return ""
}

fn test_time_diff_larger(_: String) -> String {
    let t1: Int = 1000000000000
    let t2: Int = t1 + 3600000
    assert_int_eq(time_diff(t1, t2, "min"), 60, "diff of 1 hour in minutes")
    assert_int_eq(time_diff(t1, t2, "hour"), 1, "diff of 1 hour in hours")
    assert_int_eq(time_diff(t1, t2, "ms"), 3600000, "diff of 1 hour in ms")
    return ""
}

fn test_time_diff_zero(_: String) -> String {
    let t: Int = 1000000000000
    assert_int_eq(time_diff(t, t, "ms"), 0, "same timestamp: diff is 0")
    assert_int_eq(time_diff(t, t, "sec"), 0, "same timestamp: diff in sec is 0")
    return ""
}

// ── Duration helpers ──────────────────────────────────────────────────────────

fn test_duration_helpers_basic(_: String) -> String {
    assert_int_eq(duration_seconds(1), 1000000000, "1 second = 1e9 ns")
    assert_int_eq(duration_millis(1), 1000000, "1 ms = 1e6 ns")
    assert_int_eq(duration_nanos(42), 42, "nanos identity")
    assert_int_eq(duration_to_seconds(1000000000), 1, "1e9 ns = 1 second")
    assert_int_eq(duration_to_millis(1000000), 1, "1e6 ns = 1 ms")
    assert_int_eq(duration_to_nanos(42), 42, "nanos identity roundtrip")
    return ""
}

fn test_instant_helpers_basic(_: String) -> String {
    let i: Int = unix_seconds(1000)
    assert_int_eq(i, 1000000000000, "unix_seconds(1000) = 1e12 ns")

    let ms_i: Int = unix_millis(5000)
    assert_int_eq(ms_i, 5000000000, "unix_millis(5000) = 5e9 ns")

    assert_int_eq(instant_to_unix_seconds(1000000000000), 1000, "instant to seconds")
    assert_int_eq(instant_to_unix_millis(5000000000), 5000, "instant to millis")
    return ""
}

// ── uuid_new / uuid_v4 ────────────────────────────────────────────────────────

fn test_uuid_new_basic(_: String) -> String {
    let u: String = uuid_new()
    assert_int_eq(str_len(u), 36, "UUID has 36 characters")
    assert_eq(str_char_at(u, 8), "-", "UUID has dash at position 8")
    assert_eq(str_char_at(u, 13), "-", "UUID has dash at position 13")
    assert_eq(str_char_at(u, 18), "-", "UUID has dash at position 18")
    assert_eq(str_char_at(u, 23), "-", "UUID has dash at position 23")
    return ""
}

fn test_uuid_uniqueness(_: String) -> String {
    let u1: String = uuid_new()
    let u2: String = uuid_new()
    let u3: String = uuid_v4()
    assert_false(str_eq(u1, u2), "consecutive UUIDs are different")
    assert_false(str_eq(u1, u3), "uuid_new and uuid_v4 produce different values")
    assert_false(str_eq(u2, u3), "three consecutive UUIDs are all different")
    assert_int_eq(str_len(u3), 36, "uuid_v4 also produces 36-char UUID")
    return ""
}

// ── time_from_parts ───────────────────────────────────────────────────────────

fn test_time_from_parts_basic(_: String) -> String {
    // time_from_parts(secs, ns, tz) = secs * 1000 + ns / 1000000
    let ts: Int = time_from_parts(1000, 0, "UTC")
    assert_int_eq(ts, 1000000, "1000 secs = 1000000 ms")

    let ts2: Int = time_from_parts(0, 500000000, "UTC")
    assert_int_eq(ts2, 500, "500ms in nanoseconds -> 500ms")

    let ts3: Int = time_from_parts(1705320645, 123000000, "UTC")
    assert_int_eq(ts3, 1705320645123, "known timestamp with ms component")
    return ""
}

// ── instant_to_iso8601 ────────────────────────────────────────────────────────

fn test_instant_to_iso8601_basic(_: String) -> String {
    let ts_ms: Int = 1705320645123
    let ts_ns: Int = ts_ms * 1000000
    let iso: String = instant_to_iso8601(ts_ns)
    assert_starts_with(iso, "2024-01-15", "instant_to_iso8601 correct date")
    assert_ends_with(iso, "Z", "instant_to_iso8601 ends with Z")
    return ""
}
