<script>
    /* The tap-to-sync room — the desktop's correction editor
       (LyricsSyncEditor.svelte) in the phone's idiom. The song plays and you
       tap once as each line begins; the taps become the timing. One line
       large, the line behind and the line ahead faint around it, and the
       whole middle of the screen is the tap. Saving writes the track's own
       document; lines never tapped are left out of it, and the button says
       how many are kept. */
    import Icon from "../components/Icon.svelte";
    import { nav } from "./nav.svelte.js";
    import { player, toggle, seekSecs } from "./player.svelte.js";
    import { tapSync, saveTapSync, closeTapSync } from "./lyrics.svelte.js";
    import { mmss } from "./util.js";

    /* the ✕ asks twice once there is work to lose; the back gesture keeps
       the taps instead (the lyrics sheet offers them back). The room is
       mounted for the life of the shell, so the question is put down when
       it closes — otherwise the next visit opens already asking. */
    let confirmDiscard = $state(false);
    $effect(() => { if (!nav.timing) confirmDiscard = false; });

    /* position anchors land a couple of times a second, so a tap between
       them reads the last anchor plus the wall clock — the stamp carries
       the tap's own precision rather than the tick's. Plain lets, never
       read back inside the effect that writes them. */
    let lastPos = 0;
    let lastAt = 0;
    $effect(() => {
        void player.status;
        lastPos = player.position ?? 0;
        lastAt = performance.now();
    });
    function nowMs() {
        const base = player.status === "playing"
            ? lastPos + (performance.now() - lastAt) / 1000
            : (player.position ?? 0);
        return Math.max(0, Math.round(base * 1000));
    }

    const rows = $derived(tapSync.rows);
    const done = $derived(rows.filter((r) => r.time_ms != null).length);
    const at = $derived(Math.min(tapSync.cursor, rows.length));
    const playing = $derived(player.status === "playing" || player.status === "buffering");
    /* playback moved on: a stamp would land on another song's clock */
    const wrong = $derived(!!tapSync.identity && !!player.track && player.track.title !== tapSync.identity.title);

    function stamp() {
        if (wrong || tapSync.saving || at >= rows.length) return;
        tapSync.rows[at].time_ms = nowMs();
        tapSync.cursor = at + 1;
        confirmDiscard = false;
    }
    function undo() {
        const last = tapSync.cursor - 1;
        if (last < 0) return;
        tapSync.rows[last].time_ms = null;
        tapSync.cursor = last;
    }
    function back5() { seekSecs(Math.max(0, (player.position ?? 0) - 5)); }
    function close() {
        if (done > 0 && !confirmDiscard) { confirmDiscard = true; return; }
        closeTapSync();
    }
    /* a stamp reads to a tenth — the precision a thumb actually has */
    function mark(ms) {
        if (ms == null) return "";
        return `${mmss(Math.floor(ms / 1000))}.${Math.floor((ms % 1000) / 100)}`;
    }
</script>

{#if nav.timing}
    <div class="syncroom">
        <div class="sy-head">
            <button class="iconbtn sy-close" onclick={close} aria-label={confirmDiscard ? "Discard the timing" : "Close"}>
                {#if confirmDiscard}<span class="sy-discard">Discard?</span>{:else}<Icon name="x" size={22} />{/if}
            </button>
            <span class="sy-who"><b>Tap in time</b><i>{tapSync.identity?.title ?? ""}</i></span>
            <span class="sy-count">{done} / {rows.length}</span>
        </div>

        {#if wrong}
            <div class="sy-warn">Another track is playing — a tap follows what plays. Play “{tapSync.identity?.title}” again to keep going.</div>
        {:else if tapSync.error}
            <div class="sy-warn">{tapSync.error}</div>
        {/if}

        <button class="sy-pad" onclick={stamp} disabled={wrong}>
            <span class="sy-prev">{at > 0 ? rows[at - 1].text : ""}</span>
            {#if at < rows.length}
                <span class="sy-now">{rows[at].text}</span>
                <span class="sy-next">{at + 1 < rows.length ? rows[at + 1].text : ""}</span>
                <span class="sy-hint">Tap anywhere as the line begins</span>
            {:else}
                <span class="sy-now">That’s every line — save the timing.</span>
                <span class="sy-next"></span>
                <span class="sy-hint">Undo puts the last one back</span>
            {/if}
            <span class="sy-mark">{at > 0 ? mark(rows[at - 1].time_ms) : mmss(player.position)}</span>
        </button>

        <div class="sy-foot">
            <button class="iconbtn sy-undo" onclick={undo} disabled={tapSync.cursor === 0} aria-label="Undo the last tap"><Icon name="history" size={22} /></button>
            <button class="iconbtn sy-back5" onclick={back5} aria-label="Back five seconds">−5 s</button>
            <button class="disc" onclick={toggle} aria-label={playing ? "Pause" : "Play"}><Icon name={playing ? "pause" : "play"} size={22} /></button>
            <button class="btn btn-fill sy-save" onclick={() => { void saveTapSync(); }} disabled={!done || tapSync.saving}>
                {tapSync.saving ? "Saving…" : (done && done < rows.length ? `Save ${done} line${done === 1 ? "" : "s"}` : "Save timing")}
            </button>
        </div>
    </div>
{/if}
