/* global window */
/*
 * Lonesome Goat — local storage layer
 *
 * Single namespace: "lg.v1"
 * Four collections: entries (Field Entries / Goat Notes), drafts, sketches, letters
 * One pinned slot.
 *
 * Each item shape:
 *   { id, kind, title, body|svg, location, coords, weather, wordCount, date, ts }
 *
 * Subscribers can listen for 'lg-store-change' on window to re-render.
 */

const LG_NS = "lg.v1";

const _read = (key, fallback) => {
  try { return JSON.parse(localStorage.getItem(`${LG_NS}.${key}`)) ?? fallback; }
  catch (_) { return fallback; }
};
const _write = (key, val) => {
  localStorage.setItem(`${LG_NS}.${key}`, JSON.stringify(val));
  window.dispatchEvent(new CustomEvent('lg-store-change', { detail: { key } }));
};

const LGStore = {
  // collections
  list: (kind) => _read(kind, []),
  add: (kind, item) => {
    const all = _read(kind, []);
    const withId = { id: `${kind}-${Date.now().toString(36)}-${Math.random().toString(36).slice(2,7)}`, ts: Date.now(), ...item };
    all.unshift(withId);
    _write(kind, all);
    return withId;
  },
  remove: (kind, id) => {
    const all = _read(kind, []).filter(x => x.id !== id);
    _write(kind, all);
  },
  update: (kind, id, patch) => {
    const all = _read(kind, []).map(x => x.id === id ? { ...x, ...patch } : x);
    _write(kind, all);
  },
  // active draft (autosave)
  activeDraft: () => _read('activeDraft', null),
  setActiveDraft: (v) => _write('activeDraft', v),
  clearActiveDraft: () => _write('activeDraft', null),
  // pinned
  pinned: () => _read('pinned', null),
  setPinned: (v) => _write('pinned', v),
  // mode
  mode: () => _read('mode', 'daylight'),
  setMode: (v) => _write('mode', v),
  // location preference
  locationPref: () => _read('locationPref', null),
  setLocationPref: (v) => _write('locationPref', v),
};

/* React hook to subscribe */
function useLGStore(kind) {
  const [, force] = React.useState(0);
  React.useEffect(() => {
    const onChange = (e) => {
      if (!kind || e.detail.key === kind) force(n => n + 1);
    };
    window.addEventListener('lg-store-change', onChange);
    return () => window.removeEventListener('lg-store-change', onChange);
  }, [kind]);
  return LGStore;
}

/* Browser geolocation helper (returns Promise of {label, coords} or null) */
async function getBrowserLocation() {
  if (!navigator.geolocation) return null;
  return new Promise((resolve) => {
    navigator.geolocation.getCurrentPosition(
      (pos) => {
        const { latitude: lat, longitude: lon } = pos.coords;
        const ns = lat >= 0 ? "N" : "S";
        const ew = lon >= 0 ? "E" : "W";
        resolve({
          coords: `${Math.abs(lat).toFixed(4)}° ${ns}, ${Math.abs(lon).toFixed(4)}° ${ew}`,
          lat, lon
        });
      },
      () => resolve(null),
      { enableHighAccuracy: false, timeout: 6000, maximumAge: 600000 }
    );
  });
}

/* Reverse-geocode lat/lon → human-readable place using BigDataCloud's free
 * client API (no key required). Returns a string like "Marfa, Texas" or
 * "n/a" if anything fails. */
async function reverseGeocode(lat, lon) {
  if (lat == null || lon == null) return "n/a";
  try {
    const url = `https://api.bigdatacloud.net/data/reverse-geocode-client?latitude=${lat}&longitude=${lon}&localityLanguage=en`;
    const res = await fetch(url);
    if (!res.ok) return "n/a";
    const d = await res.json();
    const city = d.city || d.locality || d.principalSubdivision;
    const region = d.principalSubdivision || d.countryName;
    if (city && region && city !== region) return `${city}, ${region}`;
    return city || region || d.countryName || "n/a";
  } catch (_) { return "n/a"; }
}

/* Current weather for given lat/lon via Open-Meteo (free, no key).
 * Returns a short string like "Partly cloudy, 72°F" or "n/a". */
const _WX_TEXT = (code) => {
  if (code === 0) return "Clear";
  if (code <= 3) return "Partly cloudy";
  if (code <= 48) return "Fog";
  if (code <= 57) return "Drizzle";
  if (code <= 67) return "Rain";
  if (code <= 77) return "Snow";
  if (code <= 82) return "Showers";
  if (code <= 86) return "Snow showers";
  if (code <= 99) return "Thunderstorm";
  return "Mild";
};
async function fetchWeather(lat, lon) {
  if (lat == null || lon == null) return "n/a";
  try {
    const url = `https://api.open-meteo.com/v1/forecast?latitude=${lat}&longitude=${lon}` +
                `&current=temperature_2m,weather_code,wind_speed_10m` +
                `&temperature_unit=fahrenheit&wind_speed_unit=mph`;
    const res = await fetch(url);
    if (!res.ok) return "n/a";
    const d = await res.json();
    const c = d.current;
    if (!c) return "n/a";
    const desc = _WX_TEXT(c.weather_code);
    const temp = Math.round(c.temperature_2m);
    return `${desc}, ${temp}°F`;
  } catch (_) { return "n/a"; }
}

/* Take a File from an <input type="file"> and return a clean data URL.
 * Downscales to a max edge of 1600px and re-encodes as JPEG @ 85% so it
 * fits comfortably in localStorage. Rejects HEIC (browsers can't render
 * it) with a friendly explanation. */
async function processUploadedImage(file) {
  if (!file || !file.type) throw new Error("That doesn't look like an image.");
  if (/heic|heif/i.test(file.type) || /\.heic$/i.test(file.name)) {
    throw new Error("HEIC photos (iPhone) aren't supported by browsers yet. Export the photo as JPG first, or take a screenshot of it.");
  }
  if (!file.type.startsWith('image/')) {
    throw new Error("That doesn't look like an image. Try JPG, PNG, GIF, or WebP.");
  }
  const dataUrl = await new Promise((resolve, reject) => {
    const r = new FileReader();
    r.onload = () => resolve(r.result);
    r.onerror = () => reject(new Error("Couldn't read that file."));
    r.readAsDataURL(file);
  });
  const img = await new Promise((resolve, reject) => {
    const im = new Image();
    im.onload = () => resolve(im);
    im.onerror = () => reject(new Error("That image format isn't supported. Try JPG, PNG, GIF, or WebP."));
    im.src = dataUrl;
  });
  const MAX = 1600;
  const scale = Math.min(MAX / img.width, MAX / img.height, 1);
  if (scale === 1 && dataUrl.length < 1500000) return dataUrl;
  const w = Math.round(img.width * scale);
  const h = Math.round(img.height * scale);
  const canvas = document.createElement('canvas');
  canvas.width = w; canvas.height = h;
  canvas.getContext('2d').drawImage(img, 0, 0, w, h);
  return canvas.toDataURL('image/jpeg', 0.85);
}

window.LGStore = LGStore;
window.useLGStore = useLGStore;
window.getBrowserLocation = getBrowserLocation;
window.reverseGeocode = reverseGeocode;
window.fetchWeather = fetchWeather;
window.processUploadedImage = processUploadedImage;
