// ApiKeyField: a secret shown masked, with a button that reveals it and one that
// copies it. The key is in a read-only field, so it can be selected, and in a
// hidden input named `name`, so a form sends it whole.
//
//   <ApiKeyField label="Live key" value="qk_live_4f9a2b7c1d3e5f6a7b8c9d0e"/>
//   <ApiKeyField label="Webhook secret" value={secret} name="secret" shown={true} hint="Shown once; copy it now."/>
//
// value: the secret. label: what it is ("API key"). id: the field's id
// ("api-key-" + name, or "api-key"). name: a hidden input with the whole value.
// keep: how many characters stay readable at each end while masked (4); the
// rest are dots. shown: starts revealed. hint: a line under it. size: "sm" or
// "md" (default). The reveal button is a toggle (aria-pressed), "Show key" or
// "Hide key"; Copy says "Copied" for a moment (and tells screen readers), or
// "Could not copy" when the browser refuses (the page is not https).
// on_reveal(shown): inside one of your components, called when it is shown or
// hidden, to log who looked.

import ui/theme.qwe use ui_cls

let api_key_field_css = css`
.ui-apikey { display: grid; gap: 6px; min-width: 0; font: 14px/1.4 var(--ui-font); color: var(--ui-fg); }
.ui-apikey-label { font-size: 13px; font-weight: 500; }
.ui-apikey-box { display: flex; align-items: stretch; min-width: 0; }
.ui-apikey-control {
  box-sizing: border-box; flex: 1; min-width: 0; height: 38px; margin: 0; padding: 0 12px;
  border: 1px solid var(--ui-border); border-radius: var(--ui-radius-sm) 0 0 var(--ui-radius-sm); background: var(--ui-subtle);
  color: var(--ui-fg); font: 13px/1 var(--ui-mono); letter-spacing: .02em; text-overflow: ellipsis; transition: border-color .15s, box-shadow .15s;
}
.ui-apikey-control:focus { outline: none; border-color: var(--ui-accent); box-shadow: var(--ui-focus); position: relative; z-index: 1; }
.ui-apikey-btn {
  display: inline-flex; align-items: center; justify-content: center; gap: 6px; height: 38px; margin-left: -1px; padding: 0 12px;
  border: 1px solid var(--ui-border); background: var(--ui-surface); color: var(--ui-muted); font: 500 13px/1 var(--ui-font); cursor: pointer;
  white-space: nowrap;
}
.ui-apikey-btn:last-child { border-radius: 0 var(--ui-radius-sm) var(--ui-radius-sm) 0; }
.ui-apikey-btn:hover { background: var(--ui-subtle); color: var(--ui-fg); }
.ui-apikey-btn:focus-visible { outline: none; box-shadow: var(--ui-focus); position: relative; z-index: 1; }
.ui-apikey-btn[aria-pressed="true"] { color: var(--ui-accent); }
.ui-apikey-btn svg { width: 16px; height: 16px; }
.ui-apikey-ok { color: var(--ui-success); }
.ui-apikey-bad { color: var(--ui-danger); }
.ui-apikey-hint { margin: 0; font-size: 13px; color: var(--ui-muted); }
.ui-apikey-sm .ui-apikey-control, .ui-apikey-sm .ui-apikey-btn { height: 30px; font-size: 12px; }
.ui-apikey-sm .ui-apikey-btn { padding: 0 9px; }
@media (max-width: 480px) { .ui-apikey-btn span { display: none; } }
@media (prefers-reduced-motion: reduce) { .ui-apikey-control { transition: none; } }
`

// The secret with its middle as dots: "qk_l••••••••••••9d0e".
fn api_key_field_mask(value: str, keep: int) -> str {
    let n = len(value)
    if n <= keep * 2 { return repeat("•", n) }
    slice(value, 0, keep) + repeat("•", min([n - keep * 2, 12])) + slice(value, n - keep, n)
}

component ApiKeyField(value: str, label: str = "API key", id: str? = null, name: str? = null, keep: int = 4, shown: bool = false,
                      hint: str? = null, size: str = "md", on_reveal = null, class: str? = null) {
    style global api_key_field_css
    state revealed = shown
    state result = ""     // "", "ok" or "bad"
    if result != "" { every(1500, () => { result = "" }) }
    let fid = id ?? (name != null ? `api-key-${name}` : "api-key")
    <div class={ui_cls(["ui-apikey", size == "sm" && "ui-apikey-sm", class])}>
        <label.ui-apikey-label for={fid}>{label}</label>
        <div.ui-apikey-box>
            <input.ui-apikey-control type="text" id={fid} value={revealed ? value : api_key_field_mask(value, keep)} readonly={true}
                   spellcheck="false" autocomplete="off" aria-describedby={hint != null ? `${fid}-hint` : null}
                   @focus={(e) => { if revealed { e.target.select() } }}/>
            <button.ui-apikey-btn type="button" aria-pressed={revealed ? "true" : "false"} aria-controls={fid}
                    aria-label={revealed ? "Hide key" : "Show key"} title={revealed ? "Hide key" : "Show key"}
                    @click={() => {
                        revealed = !revealed
                        on_reveal && on_reveal(revealed)
                    }}>
                {revealed
                    ? <svg viewBox="0 0 20 20" fill="none" stroke="currentColor" stroke-width="1.6" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M3 3l14 14"/><path d="M8.2 4.6A8.6 8.6 0 0 1 10 4.4c4.4 0 7.4 3.9 8.2 5.6-.4.8-1.2 2-2.4 3.1M12.8 15a7.9 7.9 0 0 1-2.8.6c-4.4 0-7.4-3.9-8.2-5.6.5-1 1.6-2.6 3.2-3.8"/><path d="M8.4 8.4a2.3 2.3 0 0 0 3.2 3.2"/></svg>
                    : <svg viewBox="0 0 20 20" fill="none" stroke="currentColor" stroke-width="1.6" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M1.8 10c.8-1.7 3.8-5.6 8.2-5.6s7.4 3.9 8.2 5.6c-.8 1.7-3.8 5.6-8.2 5.6S2.6 11.7 1.8 10z"/><circle cx="10" cy="10" r="2.6"/></svg>}
                <span>{revealed ? "Hide" : "Show"}</span>
            </button>
            <button class={ui_cls(["ui-apikey-btn", result != "" && `ui-apikey-${result}`])} type="button" aria-label="Copy key" title="Copy key"
                    @click={() => {
                        if js("isSecureContext") != true { result = "bad" } else {
                            js("navigator.clipboard.writeText", value).then((_ = null) => { result = "ok" }, (_ = null) => { result = "bad" })
                        }
                    }}>
                {result == "ok"
                    ? <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M20 6 9 17l-5-5"/></svg>
                    : <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M10 8h10a2 2 0 0 1 2 2v10a2 2 0 0 1-2 2H10a2 2 0 0 1-2-2V10a2 2 0 0 1 2-2ZM4 16a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h10a2 2 0 0 1 2 2"/></svg>}
                <span>{result == "ok" ? "Copied" : result == "bad" ? "Could not copy" : "Copy"}</span>
            </button>
        </div>
        {name != null && <input type="hidden" name={name} value={value}/>}
        {hint != null && <p.ui-apikey-hint id={`${fid}-hint`}>{hint}</p>}
        <span.ui-sr role="status">{result == "ok" ? "Copied" : result == "bad" ? "Could not copy" : ""}</span>
    </div>
}
