// Unit tests for parseTypedTime — the human-input time parser used by
// the executive-meetings inline time editor. Covers every shape listed
// in's "Done looks like" plus the obvious invalid edges.
//
// Runs with Node 24's built-in test runner + native TypeScript support.
import { test } from "node:test";
import assert from "node:assert/strict";
import { parseTypedTime } from "../lib/parse-time.ts";

test("returns null for empty / whitespace-only input", () => {
  assert.equal(parseTypedTime(""), null);
  assert.equal(parseTypedTime("   "), null);
  assert.equal(parseTypedTime("\t\n"), null);
});

test("canonical 24h HH:MM passes through unchanged", () => {
  assert.equal(parseTypedTime("09:30"), "09:30");
  assert.equal(parseTypedTime("00:00"), "00:00");
  assert.equal(parseTypedTime("23:59"), "23:59");
  assert.equal(parseTypedTime("12:00"), "12:00");
});

test("zero-padding is added for single-digit hours / minutes", () => {
  assert.equal(parseTypedTime("9:30"), "09:30");
  assert.equal(parseTypedTime("9:5"), "09:05");
  assert.equal(parseTypedTime("0:0"), "00:00");
});

test("compact 3-4 digit form parses as HHMM / HMM", () => {
  assert.equal(parseTypedTime("0930"), "09:30");
  assert.equal(parseTypedTime("930"), "09:30");
  assert.equal(parseTypedTime("1230"), "12:30");
  assert.equal(parseTypedTime("0000"), "00:00");
  assert.equal(parseTypedTime("2359"), "23:59");
  // 3-digit form: first digit is the hour, last two the minutes.
  assert.equal(parseTypedTime("100"), "01:00");
});

test("alternate separators (., -, whitespace) are accepted", () => {
  assert.equal(parseTypedTime("9.30"), "09:30");
  assert.equal(parseTypedTime("9-30"), "09:30");
  assert.equal(parseTypedTime("9 30"), "09:30");
  assert.equal(parseTypedTime("  9 . 30  "), "09:30");
});

test("English AM/PM markers are honoured", () => {
  assert.equal(parseTypedTime("9:30 AM"), "09:30");
  assert.equal(parseTypedTime("9:30am"), "09:30");
  assert.equal(parseTypedTime("9:30 PM"), "21:30");
  assert.equal(parseTypedTime("9:30pm"), "21:30");
  // Dotted forms.
  assert.equal(parseTypedTime("9:30 a.m."), "09:30");
  assert.equal(parseTypedTime("9:30 p.m."), "21:30");
  // 12 AM = midnight, 12 PM = noon.
  assert.equal(parseTypedTime("12:00 AM"), "00:00");
  assert.equal(parseTypedTime("12:30 AM"), "00:30");
  assert.equal(parseTypedTime("12:00 PM"), "12:00");
  assert.equal(parseTypedTime("12:30 PM"), "12:30");
});

test("Arabic AM/PM markers (ص / م) are honoured", () => {
  assert.equal(parseTypedTime("9:30 ص"), "09:30");
  assert.equal(parseTypedTime("9:30 م"), "21:30");
  assert.equal(parseTypedTime("12:00 ص"), "00:00");
  assert.equal(parseTypedTime("12:00 م"), "12:00");
  // No space between time and marker.
  assert.equal(parseTypedTime("9:30م"), "21:30");
});

test("Arabic-Indic digits (٠-٩) are mapped to ASCII", () => {
  assert.equal(parseTypedTime("٠٩:٣٠"), "09:30");
  assert.equal(parseTypedTime("٩:٣٠"), "09:30");
  assert.equal(parseTypedTime("٩:٣٠ ص"), "09:30");
  assert.equal(parseTypedTime("٩:٣٠ م"), "21:30");
  assert.equal(parseTypedTime("٢٣:٥٩"), "23:59");
});

test("Persian / Eastern Arabic-Indic digits (۰-۹) are mapped to ASCII", () => {
  assert.equal(parseTypedTime("۰۹:۳۰"), "09:30");
  assert.equal(parseTypedTime("۱۲:۴۵"), "12:45");
});

test("invalid hours/minutes return null", () => {
  assert.equal(parseTypedTime("24:00"), null);
  assert.equal(parseTypedTime("25:99"), null);
  assert.equal(parseTypedTime("9:60"), null);
  assert.equal(parseTypedTime("99:99"), null);
});

test("12-hour-only hours out of 1..12 reject when AM/PM is given", () => {
  assert.equal(parseTypedTime("0:30 AM"), null);
  assert.equal(parseTypedTime("13:00 PM"), null);
  assert.equal(parseTypedTime("13:00 ص"), null);
});

test("garbage input returns null", () => {
  assert.equal(parseTypedTime("abc"), null);
  // 3-segment form (HH:MM:SS) is rejected — we don't support seconds.
  assert.equal(parseTypedTime("9:30:45"), null);
  assert.equal(parseTypedTime(":30"), null);
  assert.equal(parseTypedTime("9:"), null);
  // 5-digit compact form is not a valid HHMM/HMM.
  assert.equal(parseTypedTime("12345"), null);
  // Mixed-with-letters input is rejected.
  assert.equal(parseTypedTime("9h30m"), null);
});

test("collapses repeated separators (lenient typo recovery)", () => {
  // Repeated separator characters are treated as one: this is a
  // deliberate "be liberal in what you accept" choice so a user who
  // double-tapped ":" or mixed "." and " " still gets a valid time
  // rather than a useless parse error.
  assert.equal(parseTypedTime("9::30"), "09:30");
  assert.equal(parseTypedTime("9.. 30"), "09:30");
});

test("non-string inputs return null", () => {
  // @ts-expect-error - intentionally testing the runtime guard
  assert.equal(parseTypedTime(null), null);
  // @ts-expect-error
  assert.equal(parseTypedTime(undefined), null);
  // @ts-expect-error
  assert.equal(parseTypedTime(930), null);
});
