// Opt-in telemetry: auto-submit lyric-timing contributions to the El Eje server so
// they can be pooled + majority-voted into shared timings. OFF by default; only runs
// after the user turns sharing on (which also grants the el-eje.com host permission).
// Sends anonymized timing data only — no full page URLs, no PII, no audio, no lyric text.
const ENABLED_KEY = "shareTimings";       // chrome.storage.local; default false
const CLIENT_KEY = "eleje_client";        // random per-install id (dedup/anti-stuffing; not PII)
const SENT_KEY = "eleje_sent";            // {contributionKey: signature} of what's been DELIVERED
const ENDPOINT = "https://el-eje.com/api/contribute";
const ORIGIN = "https://el-eje.com/*";

const hasStorage = () => typeof chrome !== "undefined" && chrome.storage && chrome.storage.local;
const keyOf = (c) => (c && (c.videoId || (c.songId ? "song:" + c.songId : null))) || null;
// Cheap content signature so an IMPROVED timing re-sends but an unchanged one doesn't.
const sig = (c) => `${(c.lines || []).length}|${c.startSec ?? ""}|${c.endSec ?? ""}`;

async function getSent() {
  if (!hasStorage()) return {};
  const o = await chrome.storage.local.get(SENT_KEY);
  return o[SENT_KEY] || {};
}

export async function isEnabled() {
  if (!hasStorage()) return false;
  const o = await chrome.storage.local.get(ENABLED_KEY);
  return o[ENABLED_KEY] === true;
}

async function clientId() {
  const o = await chrome.storage.local.get(CLIENT_KEY);
  if (o[CLIENT_KEY]) return o[CLIENT_KEY];
  const id = "c" + Math.random().toString(36).slice(2, 12);
  await chrome.storage.local.set({ [CLIENT_KEY]: id });
  return id;
}

// Anonymized wire payload — drops the full page URL and the line TEXT (the app already
// has the lyrics; only line index + time are needed to fold in the timing). Pure/testable.
export function payload(c, client) {
  return {
    v: c.v, source: c.source,
    videoId: c.videoId || null,
    songId: c.songId || null,
    song: c.song || null,
    onlineDuration: c.onlineDuration ?? null,
    startSec: c.startSec ?? null,
    endSec: c.endSec ?? null,
    lines: (c.lines || []).map((l) => ({ i: l.i, t: l.t })),
    key: keyOf(c),
    client,
  };
}

function hasPermission() {
  return new Promise((res) => {
    try { chrome.permissions.contains({ origins: [ORIGIN] }, res); } catch { res(false); }
  });
}

// Turn sharing on/off. Enabling REQUESTS the el-eje.com host permission (needs a user
// gesture — call from a click handler). Returns the resulting enabled state.
export async function setEnabled(on) {
  if (!hasStorage()) return false;
  if (on) {
    const granted = await new Promise((res) => {
      try { chrome.permissions.request({ origins: [ORIGIN] }, res); } catch { res(false); }
    });
    if (!granted) return false;          // user declined the permission -> stay off
  }
  await chrome.storage.local.set({ [ENABLED_KEY]: !!on });
  return !!on;
}

async function post(c, client) {
  await fetch(ENDPOINT, {
    method: "POST", headers: { "content-type": "application/json" },
    body: JSON.stringify(payload(c, client)),
  });
}

// Fire-and-forget submit of one contribution; no-op unless enabled + permission granted.
// On success it records delivery so it won't be re-sent; on failure (e.g. the server is
// unreachable) it stays unrecorded and submitAll() will retry it later.
export async function maybeSubmit(c) {
  try {
    if (!hasStorage() || !c || !(await isEnabled()) || !(await hasPermission())) return false;
    const k = keyOf(c);
    if (!k) return false;
    await post(c, await clientId());
    const sent = await getSent();
    sent[k] = sig(c);
    await chrome.storage.local.set({ [SENT_KEY]: sent });
    return true;
  } catch { return false; }
}

// Submit every contribution not yet DELIVERED (or whose timing changed since). Called both
// when the user opts in AND on every panel open, so anything saved while the server was
// unreachable gets delivered once it's reachable again. Already-delivered items are skipped,
// so re-running it is cheap and safe. Returns the number newly delivered.
export async function submitAll(list) {
  if (!hasStorage() || !(await isEnabled()) || !(await hasPermission())) return 0;
  const client = await clientId();
  const sent = await getSent();
  let n = 0;
  for (const c of list || []) {
    const k = keyOf(c);
    if (!k || sent[k] === sig(c)) continue;          // already delivered + unchanged -> skip
    try { await post(c, client); sent[k] = sig(c); n++; } catch { /* leave pending, retry next time */ }
  }
  if (n) await chrome.storage.local.set({ [SENT_KEY]: sent });
  return n;
}
