// ProductGallery: a product's pictures, one large with the others as thumbnails
// under it (or beside it): a click or the arrow keys switch, and a swipe on the
// large one. Screen readers hear the thumbnails as tabs and the large picture as
// their panel, with "2 of 5" as it changes.
//
//   <ProductGallery label="Trail runner" images={[
//       { src: "/p/1.jpg", alt: "From the side" },
//       { src: "/p/2.jpg", thumb: "/p/2-sm.jpg", alt: "The sole" }]}/>
//
// images: a list of { src, alt, thumb? }: src is the large picture, thumb a
// smaller one for the strip (src when there is none), alt what it shows.
// label: the product's name, for screen readers. selected: the index shown
// first (0). thumbs: "bottom" (default) or "left". ratio: the large picture's
// shape ("1"; "4/3", "3/4"). fit: "cover" (default) or "contain". arrows: the
// previous and next buttons over the picture (true). on_change(index): inside
// one of your components, given the index shown.

import ui/theme.qwe use ui_cls

let product_gallery_css = css`
.ui-pgallery { display: grid; gap: 10px; min-width: 0; font: 13px/1.4 var(--ui-font); color: var(--ui-fg); }
.ui-pgallery-left { grid-template-columns: 64px 1fr; }
.ui-pgallery-left .ui-pgallery-thumbs { order: -1; flex-direction: column; }
.ui-pgallery-stage { position: relative; aspect-ratio: var(--r, 1); overflow: hidden; border-radius: var(--ui-radius); background: var(--ui-subtle); touch-action: pan-y; }
.ui-pgallery-stage img { display: block; width: 100%; height: 100%; object-fit: var(--fit, cover); user-select: none; -webkit-user-drag: none; }
.ui-pgallery-stage:focus-visible { outline: none; box-shadow: var(--ui-focus); }
.ui-pgallery-count { position: absolute; right: 10px; bottom: 10px; padding: 2px 8px; border-radius: 999px; background: color-mix(in srgb, var(--ui-fg) 70%, transparent);
  color: var(--ui-bg); font-size: 12px; font-variant-numeric: tabular-nums; }
.ui-pgallery-nav { position: absolute; top: 50%; display: grid; place-items: center; width: 36px; height: 36px; margin-top: -18px; padding: 0;
  border: 1px solid var(--ui-border); border-radius: 50%; background: color-mix(in srgb, var(--ui-surface) 90%, transparent); color: var(--ui-fg);
  box-shadow: var(--ui-shadow); cursor: pointer; opacity: 0; transition: opacity .15s, background .15s; }
.ui-pgallery-stage:hover .ui-pgallery-nav, .ui-pgallery-nav:focus-visible, .ui-pgallery-stage:focus-within .ui-pgallery-nav { opacity: 1; }
.ui-pgallery-nav:hover { background: var(--ui-surface); }
.ui-pgallery-nav:focus-visible { outline: none; box-shadow: var(--ui-focus); }
.ui-pgallery-nav svg { width: 18px; height: 18px; }
.ui-pgallery-prev { left: 10px; }
.ui-pgallery-next { right: 10px; }
.ui-pgallery-thumbs { display: flex; gap: 8px; margin: 0; padding: 2px; overflow: auto; scrollbar-width: thin; }
.ui-pgallery-thumb { flex: none; width: 60px; height: 60px; padding: 0; overflow: hidden; border: 2px solid transparent; border-radius: var(--ui-radius-sm);
  background: var(--ui-subtle); cursor: pointer; opacity: .7; transition: opacity .15s, border-color .15s; }
.ui-pgallery-thumb img { display: block; width: 100%; height: 100%; object-fit: cover; }
.ui-pgallery-thumb:hover { opacity: 1; }
.ui-pgallery-thumb[aria-selected="true"] { opacity: 1; border-color: var(--ui-accent); }
.ui-pgallery-thumb:focus-visible { outline: none; box-shadow: var(--ui-focus); }
@media (prefers-reduced-motion: reduce) { .ui-pgallery-nav, .ui-pgallery-thumb { transition: none; } }
`

component ProductGallery(images: list = [], label: str = "Product", selected: int = 0, thumbs: str = "bottom",
                         ratio: str = "1", fit: str = "cover", arrows: bool = true, on_change = null, class: str? = null) {
    style global product_gallery_css
    state at = selected
    state sx = null
    let n = len(images)
    let cur = images[at] ?? { src: "", alt: "" }
    let go = (i: int, e) => {
        if n == 0 { return null }
        let to = (i + n) % n
        if to != at {
            at = to
            on_change && on_change(to)
        }
        if e != null {
            let tab = e.target.closest(".ui-pgallery").querySelector(`[data-i="${to}"]`)
            tab && tab.focus()
        }
    }
    let keys = (e) => {
        let to = match e.key {
            "ArrowRight" | "ArrowDown" => at + 1
            "ArrowLeft" | "ArrowUp" => at - 1
            "Home" => 0
            "End" => n - 1
            _ => null
        }
        if to != null {
            e.preventDefault()
            go(to, e)
        }
    }
    <div class={ui_cls(["ui-pgallery", thumbs == "left" && "ui-pgallery-left", class])}>
        <div.ui-pgallery-stage id={`ui-pgallery-${re.replace(lower(label), "[^a-z0-9]+", "-")}-panel`} role="tabpanel"
             aria-label={`${label}: ${cur.alt ?? ""}`} tabindex="0" style={`--r: ${ratio}; --fit: ${fit}`}
             @keydown={keys}
             @pointerdown={(e) => { sx = e.clientX }}
             @pointerup={(e) => {
                 if sx != null && abs(e.clientX - sx) > 40 { go(e.clientX < sx ? at + 1 : at - 1, null) }
                 sx = null
             }}>
            {n > 0 && <img src={cur.src} alt={cur.alt ?? ""}/>}
            {arrows && n > 1 && <button.ui-pgallery-nav.ui-pgallery-prev type="button" aria-label="Previous picture" @click={() => { go(at - 1, null) }}>
                <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="m15 6-6 6 6 6"/></svg>
            </button>}
            {arrows && n > 1 && <button.ui-pgallery-nav.ui-pgallery-next type="button" aria-label="Next picture" @click={() => { go(at + 1, null) }}>
                <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="m9 6 6 6-6 6"/></svg>
            </button>}
            {n > 1 && <span.ui-pgallery-count aria-live="polite">{at + 1}<span.ui-sr> of </span><span aria-hidden="true"> / </span>{n}</span>}
        </div>
        {n > 1 && <div.ui-pgallery-thumbs role="tablist" aria-label={`Pictures of ${label}`} @keydown={keys}>
            {for [i, im] in enumerate(images) => <button.ui-pgallery-thumb key={im.src} type="button" role="tab" data-i={i}
                    aria-selected={i == at ? "true" : "false"} aria-label={im.alt ?? `Picture ${i + 1}`} tabindex={i == at ? "0" : "-1"}
                    @click={() => { go(i, null) }}>
                <img src={get(im, "thumb") ?? im.src} alt="" loading="lazy"/>
            </button>}
        </div>}
    </div>
}
