// data.jsx — API client + dataset → in-memory species adapter.
// Source of truth: dataset.catches.world (fetched via same-origin /api/* proxy).

const API = '/api';

const HABITAT_TO_WATER = { '海水': 'Saltwater', '淡水': 'Freshwater', '咸淡水': 'Brackish' };
const WATER_TO_HABITAT = { Saltwater: '海水', Freshwater: '淡水', Brackish: '咸淡水' };
const REGION_LABEL = { CN: 'China', SEA: 'SE Asia', JP: 'Japan', US: 'United States', KR: 'Korea', AU: 'Australia', EU: 'Europe', GLOBAL: 'Global' };
const METHOD_LABEL = { lure: 'Lure', bait: 'Bait', jigging: 'Jigging', troll: 'Trolling', popping: 'Popping', fly: 'Fly', observe: 'Observe' };

// Deterministic 2-stop gradient seeded from latin name → used as fallback when no cover photo.
function gradientFromLatin(latin) {
  const palettes = [
    ['#3a4a5e', '#a8b8c8'], ['#2d4a3a', '#a8c89a'], ['#5a4a2a', '#d8b878'],
    ['#0e2a4a', '#5a8eb8'], ['#3a2a1a', '#e8c068'], ['#1a2a1a', '#6a8a4a'],
    ['#5a4a0a', '#f5d878'], ['#3a4a4a', '#c0d8d0'], ['#5a1a0a', '#e8704a'],
    ['#3a4a2a', '#aed098'], ['#0a3a4a', '#7ec8d0'], ['#1a3a2a', '#a8d088'],
    ['#4a3a1a', '#d8b888'], ['#1a1a2a', '#5a6a78'], ['#3a2a2a', '#c8a098'],
    ['#1a2a3a', '#88a8b8'], ['#3a2a0a', '#e8c878'], ['#2a2a3a', '#9a9aa8'],
    ['#1a2a1a', '#5a5a3a'], ['#3a3a1a', '#d0c878'], ['#0a4a2a', '#f5d050'],
    ['#4a2a3a', '#e89898'], ['#2a2a1a', '#7a7a5a'], ['#2a1a0a', '#8a6a4a'],
  ];
  let h = 7;
  for (const c of (latin || '')) h = (h * 31 + c.charCodeAt(0)) | 0;
  const idx = Math.abs(h) % palettes.length;
  return palettes[idx];
}

// Adapt a /api/species list record (and detail body's `.species`) into our internal Fish shape.
function adaptFish(rec) {
  const habitat = rec.habitat?.[0];
  return {
    id: rec.id || String(rec.taxon_id),
    taxon_id: rec.taxon_id,
    name: rec.en_name || rec.scientific_name,
    latin: rec.scientific_name,
    family: rec.family || '',
    water: HABITAT_TO_WATER[habitat] || 'Saltwater',
    habitat: habitat || '',
    methods: rec.fishing_methods || [],
    regions: rec.regions || [],
    aliases:    rec.aliases    || [],
    en_aliases: rec.en_aliases || [],
    zh_aliases: rec.zh_aliases || [],
    description: rec.species_description || '',
    adult_id_notes:    rec.adult_id_notes    || '',
    juvenile_id_notes: rec.juvenile_id_notes || '',
    recommended_baits: rec.recommended_baits || '',
    recommended_lures: rec.recommended_lures || '',
    is_common: !!rec.is_common,
    image_count: rec.image_count || 0,
    cover_idx:   rec.cover_idx,
    coverImg: (rec.cover_idx != null && rec.image_count > 0)
      ? `${API}/image/${rec.taxon_id}/${rec.cover_idx}`
      : null,
    gradient: gradientFromLatin(rec.scientific_name),
    taxonomy: rec.taxonomy || null,
  };
}

function imgUrl(taxonId, idx) {
  return `${API}/image/${taxonId}/${idx}`;
}

// Fetch list of all species. Returns array of adapted Fish objects.
async function fetchSpecies() {
  const r = await fetch(`${API}/species`, { headers: { Accept: 'application/json' } });
  if (!r.ok) throw new Error(`fetchSpecies: HTTP ${r.status}`);
  const data = await r.json();
  return (data.species || []).map(adaptFish);
}

// Fetch full detail for one species (id can be slug or numeric taxon_id).
async function fetchSpeciesDetail(id) {
  const r = await fetch(`${API}/species/${encodeURIComponent(id)}`, { headers: { Accept: 'application/json' } });
  if (!r.ok) throw new Error(`fetchSpeciesDetail(${id}): HTTP ${r.status}`);
  const data = await r.json();
  return {
    fish: adaptFish(data.species),
    images: (data.images || []).map((img) => ({
      ...img,
      url: imgUrl(data.species.taxon_id, img.idx),
    })),
  };
}

// Compute facet values + counts from the loaded species array.
function computeFacets(species) {
  const water = new Map(); const method = new Map(); const family = new Map(); const region = new Map();
  let common = 0;
  for (const f of species) {
    if (f.water) water.set(f.water, (water.get(f.water) || 0) + 1);
    for (const m of f.methods) method.set(m, (method.get(m) || 0) + 1);
    if (f.family) family.set(f.family, (family.get(f.family) || 0) + 1);
    for (const r of f.regions) region.set(r, (region.get(r) || 0) + 1);
    if (f.is_common) common++;
  }
  const sorted = (m, limit) => [...m.entries()].sort((a, b) => b[1] - a[1]).slice(0, limit);
  return {
    Water:  sorted(water,  10),
    Method: sorted(method, 12),
    Family: sorted(family, 14),
    Region: sorted(region, 12),
    common,
  };
}

Object.assign(window, {
  fetchSpecies, fetchSpeciesDetail,
  adaptFish, gradientFromLatin, imgUrl, computeFacets,
  HABITAT_TO_WATER, WATER_TO_HABITAT, REGION_LABEL, METHOD_LABEL,
});
