// Web-game-portal integration (CrazyGames today; the shape is deliberately
// portal-agnostic so Yandex/GameDistribution can slot in behind the same API).
//
// On the plain web build TARGET is 'web' and every call here is a no-op that
// resolves immediately, so game.js never has to branch on the target.

import { TARGET } from './build-target.js';

export const PORTAL = TARGET === 'web' ? null : TARGET;
// portal builds ship no server: the match runs in the browser (local/host.js)
export const OFFLINE = PORTAL !== null;

const SDK_SRC = {
  crazygames: 'https://sdk.crazygames.com/crazygames-sdk-v3.js',
};

let sdk = null;          // the live SDK namespace, or null when unavailable
let ready = null;        // in-flight init promise

function loadScript(src) {
  return new Promise((resolve, reject) => {
    const el = document.createElement('script');
    el.src = src;
    el.onload = resolve;
    el.onerror = () => reject(new Error('sdk load failed'));
    document.head.appendChild(el);
  });
}

// Never let a portal SDK take the game down with it: every failure path here
// leaves `sdk` null and the game plays on exactly as it does on the web build.
export function initPortal() {
  if (ready) return ready;
  if (!PORTAL) return (ready = Promise.resolve(false));
  ready = (async () => {
    try {
      await loadScript(SDK_SRC[PORTAL]);
      await window.CrazyGames.SDK.init();
      sdk = window.CrazyGames.SDK;
      return true;
    } catch (err) {
      console.warn('portal sdk unavailable:', err.message);
      sdk = null;
      return false;
    }
  })();
  return ready;
}

const call = (fn) => { try { fn(); } catch { /* SDK hiccup, keep playing */ } };

export const loadingStart = () => sdk && call(() => sdk.game.loadingStart());
export const loadingStop = () => sdk && call(() => sdk.game.loadingStop());
export const gameplayStart = () => sdk && call(() => sdk.game.gameplayStart());
export const gameplayStop = () => sdk && call(() => sdk.game.gameplayStop());
export const happytime = () => sdk && call(() => sdk.game.happytime());

// Resolves { shown } — false means no ad ran (no SDK, adblock, cooldown,
// unfilled). Callers must not reward the player unless `shown` is true.
export function requestAd(type) {
  if (!sdk) return Promise.resolve({ shown: false, error: 'nosdk' });
  return new Promise((resolve) => {
    let settled = false;
    const done = (result) => { if (!settled) { settled = true; resolve(result); } };
    call(() => sdk.ad.requestAd(type, {
      adStarted: () => {},
      adFinished: () => done({ shown: true }),
      adError: (error) => done({ shown: false, error: String(error?.code || error || 'error') }),
    }));
    // an SDK that never calls back must not strand the player mid-menu
    setTimeout(() => done({ shown: false, error: 'timeout' }), 90_000);
  });
}

// The portal owns a mute switch of its own (and `?muteAudio=true` for testing);
// the guidelines say it takes priority over the game's volume sliders. Calls
// `apply` once with the current settings and again on every change.
export function watchSettings(apply) {
  if (!sdk) return;
  const push = (settings) => apply({ muteAudio: Boolean(settings?.muteAudio) });
  call(() => push(sdk.game.settings));
  call(() => sdk.game.addSettingsChangeListener(push));
}

export async function hasAdblock() {
  if (!sdk) return false;
  try { return await sdk.ad.hasAdblock(); } catch { return false; }
}
