/**
 * Pharmacies from OpenStreetMap via Overpass API (no API key).
 * @see https://wiki.openstreetmap.org/wiki/Overpass_API
 */

import { osmElementToPharmacy } from './normalize.js';

const OVERPASS_ENDPOINTS = (
  process.env.OVERPASS_API_URL ||
  'https://overpass-api.de/api/interpreter,https://overpass.openstreetmap.fr/api/interpreter'
)
  .split(',')
  .map((s) => s.trim())
  .filter(Boolean);

function buildOverpassQuery(lat, lon, radiusM) {
  // Nodes only (fast); ways/relations are rarer for pharmacies and heavy on public Overpass.
  return `[out:json][timeout:25];
(
  node["amenity"="pharmacy"](around:${radiusM},${lat},${lon});
  node["healthcare"="pharmacy"](around:${radiusM},${lat},${lon});
);
out;`;
}

const FETCH_MS = 35000;

async function fetchOverpass(endpoint, body) {
  const ctrl = new AbortController();
  const timer = setTimeout(() => ctrl.abort(), FETCH_MS);
  try {
    return await fetch(endpoint, {
      method: 'POST',
      signal: ctrl.signal,
      headers: {
        'Content-Type': 'application/x-www-form-urlencoded',
        Accept: 'application/json',
        'User-Agent': 'FarmaClic/1.0 (OSM pharmacy import; local admin)',
      },
      body,
    });
  } finally {
    clearTimeout(timer);
  }
}

/**
 * @param {{ lat: number, lon: number, radiusMeters?: number }} opts
 * @returns {Promise<Array<{name,address,phone,latitude,longitude}>>}
 */
export async function fetchPharmaciesFromOsm({ lat, lon, radiusMeters = 1500 }) {
  const latN = Number(lat);
  const lonN = Number(lon);
  if (!Number.isFinite(latN) || !Number.isFinite(lonN)) {
    throw new Error('fetchPharmaciesFromOsm: invalid lat or lon');
  }
  const r = Math.round(
    Math.min(Math.max(Number(radiusMeters) || 1500, 50), 25000)
  );

  const body = `data=${encodeURIComponent(buildOverpassQuery(latN, lonN, r))}`;
  let lastErr = null;
  let json = null;
  let text = '';

  for (const endpoint of OVERPASS_ENDPOINTS) {
    let res;
    try {
      res = await fetchOverpass(endpoint, body);
    } catch (e) {
      lastErr =
        e.name === 'AbortError'
          ? new Error(`Overpass timeout (${FETCH_MS / 1000}s) at ${new URL(endpoint).host}`)
          : e;
      continue;
    }
    text = await res.text();
    let parsed;
    try {
      parsed = text ? JSON.parse(text) : {};
    } catch {
      lastErr = new Error(
        `Overpass returned non-JSON (HTTP ${res.status}): ${(text || '').slice(0, 120)}`
      );
      continue;
    }
    if (!res.ok && (res.status === 504 || res.status === 502 || res.status === 429)) {
      lastErr = new Error(
        `Overpass busy (HTTP ${res.status}) at ${new URL(endpoint).host}`
      );
      continue;
    }
    if (!res.ok) {
      const msg = parsed.remark || parsed.error || text.slice(0, 200);
      throw new Error(`Overpass HTTP ${res.status}: ${msg}`);
    }
    json = parsed;
    lastErr = null;
    break;
  }

  if (lastErr && !json) {
    throw lastErr;
  }
  if (!json || !Array.isArray(json.elements)) {
    throw lastErr || new Error('Overpass: no usable response');
  }

  const elements = json.elements;
  const seen = new Set();
  const out = [];

  for (const el of elements) {
    const key = `${el.type}/${el.id}`;
    if (seen.has(key)) continue;
    seen.add(key);
    const row = osmElementToPharmacy(el);
    if (row.name && row.address) {
      out.push(row);
    }
  }

  return out;
}
