/**
 * Safe localStorage wrapper. Falls back to an in-memory map when storage is
 * unavailable (private mode, quota exceeded, sandboxed iframe) so the game
 * never crashes on a storage call.
 */

export const KEYS = {
  best: 'naddie_best_score',
  muted: 'naddie_muted',
  volume: 'naddie_volume',
  tutorialSeen: 'naddie_tutorial_seen',
  achievements: 'naddie_achievements_v1',
  particleQuality: 'naddie_particle_quality',
  background: 'naddie_background',
  stats: 'naddie_stats_v1',
  dailyPrefix: 'naddie_daily_',
};

const memory = new Map();
let available = null;

function isAvailable() {
  if (available !== null) return available;
  try {
    const testKey = '__naddie_test__';
    window.localStorage.setItem(testKey, '1');
    window.localStorage.removeItem(testKey);
    available = true;
  } catch (_) {
    available = false;
  }
  return available;
}

export const storage = {
  getItem(key, fallback = null) {
    try {
      if (isAvailable()) {
        const v = window.localStorage.getItem(key);
        return v === null ? fallback : v;
      }
    } catch (_) {}
    return memory.has(key) ? memory.get(key) : fallback;
  },

  setItem(key, value) {
    const str = String(value);
    try {
      if (isAvailable()) {
        window.localStorage.setItem(key, str);
        return;
      }
    } catch (_) {}
    memory.set(key, str);
  },

  removeItem(key) {
    try {
      if (isAvailable()) window.localStorage.removeItem(key);
    } catch (_) {}
    memory.delete(key);
  },

  getInt(key, fallback = 0) {
    const raw = this.getItem(key, null);
    if (raw === null) return fallback;
    const n = parseInt(raw, 10);
    return Number.isFinite(n) ? n : fallback;
  },

  getFloat(key, fallback = 0) {
    const raw = this.getItem(key, null);
    if (raw === null) return fallback;
    const n = parseFloat(raw);
    return Number.isFinite(n) ? n : fallback;
  },

  getJSON(key, fallback = null) {
    const raw = this.getItem(key, null);
    if (raw === null) return fallback;
    try {
      return JSON.parse(raw);
    } catch (_) {
      return fallback;
    }
  },

  setJSON(key, obj) {
    try {
      this.setItem(key, JSON.stringify(obj));
    } catch (_) {}
  },
};
