// WorldClock: the time now in several places, ticking each minute in the browser, each
// with its city, the day there (Today, Tomorrow, Yesterday) and its difference from the
// first one (+5h, −8h). Night hours are shaded. The server writes the time when it makes
// the page, so it reads right before any script runs.
//
//   <WorldClock zones={[{ city: "Lisbon", zone: "Europe/Lisbon" }, { city: "New York", zone: "America/New_York" },
//                       { city: "Tokyo", zone: "Asia/Tokyo" }]}/>
//   <WorldClock zones={team} hour12={true} seconds={true} variant="list"/>
//
// zones: a list of { city, zone (an IANA name: "Europe/Paris", "UTC", or an offset
// "+05:30"), note? (a line under the city: "Ana, Ben") }. The first is home: the others
// say how far ahead or behind it they are, and which day it is there next to its day.
// hour12: a 12-hour clock with AM/PM. seconds: show and tick the seconds too.
// variant: "cards" (default, a row of tiles) or "list" (rows). at: a fixed moment to show
// (an ISO date-time with an offset) instead of now, which then does not tick.
// label: what screen readers call it ("World clock").

import ui/theme.qwe use ui_cls

let world_clock_css = css`
.ui-world-clock { display: grid; grid-template-columns: repeat(auto-fill, minmax(150px, 1fr)); gap: 10px; min-width: 0; margin: 0; padding: 0; list-style: none; font: 13px/1.35 var(--ui-font); color: var(--ui-fg); }
.ui-world-clock-zone { display: grid; gap: 2px; padding: 12px 14px; border: 1px solid var(--ui-border); border-radius: var(--ui-radius); background: var(--ui-surface); }
.ui-world-clock-night { background: color-mix(in srgb, var(--ui-fg) 6%, var(--ui-surface)); }
.ui-world-clock-city { display: flex; align-items: center; justify-content: space-between; gap: 6px; font-weight: 600; }
.ui-world-clock-city svg { flex: none; width: 14px; height: 14px; color: var(--ui-muted); }
.ui-world-clock-time { font-size: 28px; font-weight: 650; line-height: 1.15; font-variant-numeric: tabular-nums; letter-spacing: -.01em; }
.ui-world-clock-time small { margin-left: 3px; font-size: 13px; font-weight: 600; color: var(--ui-muted); letter-spacing: 0; }
.ui-world-clock-meta { color: var(--ui-muted); font-size: 12px; }
.ui-world-clock-note { color: var(--ui-muted); font-size: 12px; }
.ui-world-clock-list { grid-template-columns: 1fr; gap: 0; border: 1px solid var(--ui-border); border-radius: var(--ui-radius); overflow: hidden; }
.ui-world-clock-list .ui-world-clock-zone { grid-template-columns: minmax(0, 1fr) auto; align-items: center; gap: 0 12px; border: 0; border-radius: 0; border-top: 1px solid var(--ui-border); }
.ui-world-clock-list .ui-world-clock-zone:first-child { border-top: 0; }
.ui-world-clock-list .ui-world-clock-time { grid-column: 2; grid-row: 1 / span 3; font-size: 22px; text-align: right; }
`

// Minutes east of UTC of an offset written "+05:30", "-04:00" or "Z".
fn world_clock_offset(o: str) -> int {
    if o == "Z" || o == "" { return 0 }
    let sign = starts_with(o, "-") ? -1 : 1
    sign * ((int(slice(o, 1, 3)) ?? 0) * 60 + (int(slice(o, 4, 6)) ?? 0))
}

// The difference between two offsets, as it reads: 300 is "+5h", -210 is "−3h 30m", 0 is "same time".
fn world_clock_diff(m: int) -> str {
    if m == 0 { return "same time" }
    let a = abs(m)
    `${m > 0 ? "+" : "−"}${floor(a / 60)}h${a % 60 != 0 ? ` ${a % 60}m` : ""}`
}

component WorldClock(zones: list = [], hour12: bool = false, seconds: bool = false, variant: str = "cards", at: str? = null,
                     label: str = "World clock", class: str? = null) {
    style global world_clock_css
    state tick = now()
    let fixed = at != null ? date.ms(at) : null
    let ms = fixed ?? tick
    if fixed == null {
        every(seconds ? 1000 : 15000, () => { tick = now() })
    }
    let two = (n: int) => n < 10 ? `0${n}` : str(n)
    let home = len(zones) > 0 ? date.from_ms(ms, zones[0].zone) : null
    let home_day = home != null ? slice(home, 0, 10) : null
    let home_off = home != null ? world_clock_offset(slice(home, 19, len(home))) : 0
    <ul class={ui_cls(["ui-world-clock", variant == "list" && "ui-world-clock-list", class])} aria-label={label}>
        {for [i, z] in enumerate(zones) => {
            let t = date.from_ms(ms, z.zone)
            let p = date.parts(t)
            let day = slice(t, 0, 10)
            let off = world_clock_offset(slice(t, 19, len(t)))
            let word = day == home_day ? "Today" : (day > home_day ? "Tomorrow" : "Yesterday")
            let h = hour12 ? (p.hour % 12 == 0 ? 12 : p.hour % 12) : p.hour
            let clock = `${hour12 ? str(h) : two(h)}:${two(p.minute)}${seconds ? `:${two(p.second)}` : ""}`
            let ampm = hour12 ? (p.hour < 12 ? "AM" : "PM") : null
            let night = p.hour < 6 || p.hour >= 20
            <li key={`${z.city}-${i}`} class={ui_cls(["ui-world-clock-zone", night && "ui-world-clock-night"])}
                aria-label={`${z.city}: ${clock}${ampm != null ? ` ${ampm}` : ""}, ${date.format(day, "dddd")}${i > 0 ? `, ${world_clock_diff(off - home_off)}` : ""}`}>
                <span.ui-world-clock-city aria-hidden="true">
                    {z.city}
                    {night
                        ? <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M21 12.8A9 9 0 1 1 11.2 3a7 7 0 0 0 9.8 9.8z"/></svg>
                        : <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="4"/><path d="M12 2v2M12 20v2M4.9 4.9l1.4 1.4M17.7 17.7l1.4 1.4M2 12h2M20 12h2M4.9 19.1l1.4-1.4M17.7 6.3l1.4-1.4"/></svg>}
                </span>
                <time.ui-world-clock-time datetime={t} aria-hidden="true">{clock}{ampm != null && <small>{ampm}</small>}</time>
                <span.ui-world-clock-meta aria-hidden="true">{word}{i > 0 ? `, ${world_clock_diff(off - home_off)}` : ""}</span>
                {z.note != null && <span.ui-world-clock-note>{z.note}</span>}
            </li>
        }}
    </ul>
}
