/* Taste: what this device has told the Soulseek server it likes and what
   it hates, and the people the server ranks as close to it. The desktop
   keeps all three in `community.svelte.js` and follows one rule — the
   ranking only moves when its input does, so every declaration asks the
   server again and the chips stay quiet until it has answered. The lists
   are THIS CLIENT's: the backend keeps them and re-declares every one of
   them at login, because the server's own copy belongs to the account and
   another client signed in elsewhere can change it under us. */
import * as api from "../lib/api.js";
import { slsk } from "./slsk.svelte.js";
import { player } from "./player.svelte.js";

export const taste = $state({
    /** the things declared, as the backend last answered */
    likes: [],
    hates: [],
    /** null until asked; { users: [{ username, rating }] } after */
    similar: null,
    /** a declaration in flight, so the chips go quiet */
    busy: false,
    asking: false,
    /** the server's word when it would not answer */
    error: "",
});

/* the account these lists were read for — a plain variable, never $state:
   the screen's effect is what calls loadTaste, and reading this inside it
   would arm that effect on our own write */
let readFor = null;

/** What this device has declared. Once per account, unless forced. */
export async function loadTaste(force = false) {
    const who = slsk.username || slsk.savedUser || "";
    if (readFor === who && !force) return;
    readFor = who;
    try {
        const v = await api.slskInterestsMine();
        taste.likes = v?.likes ?? [];
        taste.hates = v?.hates ?? [];
    } catch (e) {
        player.error = String(e);
    }
    await askSimilar(true);
}

/** Declare a thing, or take it back. The backend answers with both lists,
 *  and the server's match is asked again before the chips come back — it
 *  ranks on exactly this, so a second declaration must not overtake it. */
export async function setInterest(thing, like, on) {
    const t = String(thing || "").trim();
    if (!t || taste.busy) return false;
    taste.busy = true;
    try {
        const v = await api.slskInterestSet(t, like, on);
        taste.likes = v?.likes ?? [];
        taste.hates = v?.hates ?? [];
        await askSimilar(true);
        return true;
    } catch (e) {
        player.error = String(e);
        return false;
    } finally {
        taste.busy = false;
    }
}

/** The people the server puts near us, by the likes we declared. */
export async function askSimilar(force = false) {
    if ((taste.similar && !force) || taste.asking) return;
    taste.asking = true;
    taste.error = "";
    try {
        taste.similar = { users: (await api.slskSimilarUsers()) || [] };
    } catch (e) {
        taste.similar = { users: [] };
        taste.error = String(e);
    } finally {
        taste.asking = false;
    }
}
