/* ============================================================
   Live data layer — keys are read from Settings (localStorage),
   falling back to the defaults below. Settings → API Keys lets
   the user override any of them. NOTE: client-side keys are
   visible to anyone who opens the page; proxy via a backend for
   production.
   ============================================================ */
const DEFAULT_KEYS = {
  locationiq: 'pk.5943be25b3186eafb7d7ed7c8f2d09e4',
  apininjas: 'Ad9QWA8Y4YRa7mlUUNYb3NjjMOW70cnNgk9OUh29',
  rentcast: '2165ce24555842cea790cb7393fc7260',
  geoapify: '',
  google: 'AIzaSyBY8ssPT9EzG9ZdBMGTCbT7GQm4rGSUx38',
  greatschools: '',
  walkscore: '',
};
const SETTINGS_KEY = 'casabilia-settings-v1';
function getSettings() {
  try { return JSON.parse(localStorage.getItem(SETTINGS_KEY)) || {}; } catch (e) { return {}; }
}
function getApiKey(name) {
  const s = getSettings();
  const k = s.keys && s.keys[name];
  return (k && k.trim()) ? k.trim() : (DEFAULT_KEYS[name] || '');
}
// Back-compat shim
const API_KEYS = new Proxy({}, { get: (_, name) => getApiKey(name) });

function withTimeout(promise, ms = 9000) {
  return Promise.race([
    promise,
    new Promise((_, rej) => setTimeout(() => rej(new Error('timeout')), ms)),
  ]);
}

const US_STATES = {
  alabama: 'AL', alaska: 'AK', arizona: 'AZ', arkansas: 'AR', california: 'CA', colorado: 'CO',
  connecticut: 'CT', delaware: 'DE', 'district of columbia': 'DC', florida: 'FL', georgia: 'GA',
  hawaii: 'HI', idaho: 'ID', illinois: 'IL', indiana: 'IN', iowa: 'IA', kansas: 'KS', kentucky: 'KY',
  louisiana: 'LA', maine: 'ME', maryland: 'MD', massachusetts: 'MA', michigan: 'MI', minnesota: 'MN',
  mississippi: 'MS', missouri: 'MO', montana: 'MT', nebraska: 'NE', nevada: 'NV', 'new hampshire': 'NH',
  'new jersey': 'NJ', 'new mexico': 'NM', 'new york': 'NY', 'north carolina': 'NC', 'north dakota': 'ND',
  ohio: 'OH', oklahoma: 'OK', oregon: 'OR', pennsylvania: 'PA', 'rhode island': 'RI', 'south carolina': 'SC',
  'south dakota': 'SD', tennessee: 'TN', texas: 'TX', utah: 'UT', vermont: 'VT', virginia: 'VA',
  washington: 'WA', 'west virginia': 'WV', wisconsin: 'WI', wyoming: 'WY',
};
function toStateAbbr(s) {
  if (!s) return '';
  const t = s.toString().trim();
  if (t.length === 2) return t.toUpperCase();
  return US_STATES[t.toLowerCase()] || t.slice(0, 2).toUpperCase();
}

/* ---- Geocoding: LocationIQ primary, API Ninjas fallback ---- */
async function geocode(address) {
  // 1) LocationIQ — supports browser CORS + gives a static-map photo
  try {
    const url = `https://us1.locationiq.com/v1/search?key=${API_KEYS.locationiq}&q=${encodeURIComponent(address)}&format=json&addressdetails=1&normalizeaddress=1&limit=1`;
    const r = await withTimeout(fetch(url));
    if (r.ok) {
      const d = await r.json();
      if (Array.isArray(d) && d[0]) {
        const a = d[0].address || {};
        return {
          ok: true, via: 'LocationIQ',
          lat: parseFloat(d[0].lat), lon: parseFloat(d[0].lon),
          display: d[0].display_name,
          house: a.house_number || '', road: a.road || '',
          city: a.city || a.town || a.village || a.hamlet || a.suburb || '',
          state: (a.state_code || a.state || '').toString().length === 2 ? (a.state_code || a.state).toUpperCase() : toStateAbbr(a.state || a.state_code),
          zip: a.postcode || '',
        };
      }
    }
  } catch (e) { /* fall through */ }

  // 2) API Ninjas geocoding fallback (city/state granularity)
  try {
    const parts = address.split(',').map((s) => s.trim());
    const city = parts.length >= 2 ? parts[parts.length - 2] : parts[0];
    const stateZip = parts[parts.length - 1] || '';
    const st = (stateZip.match(/[A-Za-z]{2}/) || [''])[0];
    const url = `https://api.api-ninjas.com/v1/geocoding?city=${encodeURIComponent(city)}${st ? '&state=' + st : ''}&country=US`;
    const r = await withTimeout(fetch(url, { headers: { 'X-Api-Key': API_KEYS.apininjas } }));
    if (r.ok) {
      const d = await r.json();
      if (Array.isArray(d) && d[0]) {
        return { ok: true, via: 'API Ninjas', lat: d[0].latitude, lon: d[0].longitude, city: d[0].name, state: toStateAbbr(d[0].state || st), zip: (stateZip.match(/\d{5}/) || [''])[0] };
      }
    }
  } catch (e) { /* fall through */ }

  return { ok: false };
}

function staticMapUrl(lat, lon) {
  if (!lat || !lon) return '';
  return `https://maps.locationiq.com/v3/staticmap?key=${API_KEYS.locationiq}&center=${lat},${lon}&zoom=18&size=640x380&scale=2&maptype=satellite&markers=icon:large-red-cutout|${lat},${lon}`;
}

/* ---- RentCast: direct browser call (CORS is allowed) ---- */
async function rentcastGet(path) {
  const url = 'https://api.rentcast.io/v1' + path;
  try {
    const r = await withTimeout(fetch(url, { headers: { 'X-Api-Key': API_KEYS.rentcast, accept: 'application/json' } }), 9000);
    let data = null;
    try { data = await r.json(); } catch (e) { /* non-json */ }
    if (r.ok) return { ok: true, via: 'RentCast', data };
    const detail = data && (data.error || data.message) ? [data.error, data.message].filter(Boolean).join(': ') : ('HTTP ' + r.status);
    return { ok: false, status: r.status, error: detail };
  } catch (e) {
    return { ok: false, error: 'network: ' + e.message };
  }
}

async function fetchProperty(address) {
  const r = await rentcastGet('/properties?address=' + encodeURIComponent(address));
  if (r.ok) {
    const rec = Array.isArray(r.data) ? r.data[0] : r.data;
    if (rec) {
      // Normalize tax history (RentCast keys by year)
      const taxes = Object.values(rec.propertyTaxes || {}).map((t) => ({ year: t.year, total: t.total }));
      const assess = Object.values(rec.taxAssessments || {}).map((a) => ({ year: a.year, value: a.value, land: a.land, improvements: a.improvements }));
      return {
        ok: true, via: r.via,
        beds: rec.bedrooms, baths: rec.bathrooms, sqft: rec.squareFootage,
        lotSize: rec.lotSize ? +(rec.lotSize / 43560).toFixed(2) : undefined,
        yearBuilt: rec.yearBuilt, type: rec.propertyType, owner: (rec.owner && rec.owner.names && rec.owner.names[0]) || '',
        lastSale: rec.lastSalePrice, lastSaleDate: rec.lastSaleDate,
        taxes: taxes.sort((a, b) => b.year - a.year), assess: assess.sort((a, b) => b.year - a.year),
      };
    }
  }
  return { ok: false, error: r.error };
}

async function fetchValue(address) {
  const r = await rentcastGet('/avm/value?address=' + encodeURIComponent(address));
  if (r.ok && r.data && r.data.price) {
    return { ok: true, via: r.via, low: r.data.priceRangeLow, mid: r.data.price, high: r.data.priceRangeHigh, comps: (r.data.comparables || []).length };
  }
  return { ok: false, error: r.error };
}

/* ---- Comparable sales (from AVM value endpoint) ---- */
async function fetchComps(address) {
  const r = await rentcastGet('/avm/value?address=' + encodeURIComponent(address));
  if (r.ok && r.data && Array.isArray(r.data.comparables)) {
    const comps = r.data.comparables.slice(0, 8).map((c) => ({
      address: (c.formattedAddress || '').split(',')[0],
      price: c.price, sqft: c.squareFootage,
      ppsf: c.squareFootage ? Math.round(c.price / c.squareFootage) : 0,
      beds: c.bedrooms, baths: c.bathrooms,
      dom: c.daysOnMarket, dist: c.distance, year: c.yearBuilt,
      correlation: c.correlation,
    }));
    const ppsfs = comps.filter((c) => c.ppsf > 0).map((c) => c.ppsf);
    const doms = comps.filter((c) => c.dom != null).map((c) => c.dom);
    return {
      ok: true, via: r.via, comps,
      avgPrice: Math.round(r.data.price),
      avgPpsf: ppsfs.length ? Math.round(ppsfs.reduce((a, b) => a + b, 0) / ppsfs.length) : 0,
      avgDom: doms.length ? Math.round(doms.reduce((a, b) => a + b, 0) / doms.length) : 0,
    };
  }
  return { ok: false, error: r.error };
}

async function fetchRent(address) {
  const r = await rentcastGet('/avm/rent/long-term?address=' + encodeURIComponent(address));
  if (r.ok && r.data && r.data.rent) {
    return { ok: true, via: r.via, low: r.data.rentRangeLow, mid: r.data.rent, high: r.data.rentRangeHigh, comps: (r.data.comparables || []).length };
  }
  return { ok: false, error: r.error };
}

/* ---- LocationIQ address autocomplete ---- */
async function autocomplete(query) {
  if (!query || query.length < 3) return [];
  try {
    const url = `https://api.locationiq.com/v1/autocomplete?key=${getApiKey('locationiq')}&q=${encodeURIComponent(query)}&limit=6&countrycodes=us&tag=place:house,place:building,highway&dedupe=1`;
    const r = await withTimeout(fetch(url), 6000);
    if (r.ok) {
      const d = await r.json();
      if (Array.isArray(d)) return d.map((x) => ({ label: x.display_place ? (x.display_place + (x.display_address ? ', ' + x.display_address : '')) : x.display_name, full: x.display_name, lat: +x.lat, lon: +x.lon, a: x.address || {} }));
    }
  } catch (e) { /* ignore */ }
  return [];
}

/* ---- FEMA National Flood Hazard Layer (free, no key) ---- */
async function floodZone(lat, lon) {
  if (!lat || !lon) return { ok: false };
  try {
    const url = `https://hazards.fema.gov/arcgis/rest/services/public/NFHL/MapServer/28/query?geometry=${lon},${lat}&geometryType=esriGeometryPoint&inSR=4326&spatialRel=esriSpatialRelIntersects&outFields=FLD_ZONE,ZONE_SUBTY&returnGeometry=false&f=json`;
    const r = await withTimeout(fetch(url), 8000);
    if (r.ok) {
      const d = await r.json();
      const f = d.features && d.features[0] && d.features[0].attributes;
      if (f) return { ok: true, zone: f.FLD_ZONE, subtype: f.ZONE_SUBTY || '' };
      return { ok: true, zone: 'X', subtype: 'Outside mapped high-risk area' };
    }
  } catch (e) { /* ignore */ }
  return { ok: false };
}

/* ---- Drive time via LocationIQ Directions ---- */
async function driveTime(fromLat, fromLon, toQuery) {
  try {
    const g = await geocode(toQuery);
    if (!g.ok) return { ok: false };
    const url = `https://us1.locationiq.com/v1/directions/driving/${fromLon},${fromLat};${g.lon},${g.lat}?key=${getApiKey('locationiq')}&overview=false`;
    const r = await withTimeout(fetch(url), 8000);
    if (r.ok) {
      const d = await r.json();
      const rt = d.routes && d.routes[0];
      if (rt) return { ok: true, minutes: Math.round(rt.duration / 60), miles: +(rt.distance / 1609.34).toFixed(1), to: g.display };
    }
  } catch (e) { /* ignore */ }
  return { ok: false };
}

function streetViewUrl(lat, lon, w = 640, h = 360) {
  const key = getApiKey('google');
  if (!key || !lat) return '';
  return `https://maps.googleapis.com/maps/api/streetview?size=${w}x${h}&location=${lat},${lon}&fov=80&pitch=0&key=${key}`;
}

function streetViewEmbedUrl(lat, lon) {
  const key = getApiKey('google');
  if (!key || !lat) return '';
  return `https://www.google.com/maps/embed/v1/streetview?key=${key}&location=${lat},${lon}&fov=80&pitch=0`;
}

/* ---- Quick links to listing portals for an address ---- */
function buildListingLinks(p) {
  const parts = [p.address, p.city, p.state, p.zip].filter(Boolean).join(' ').trim();
  const enc = encodeURIComponent(parts);
  const dash = parts.replace(/,/g, '').replace(/\s+/g, '-');
  const under = [(p.address || '').trim().replace(/\s+/g, '-'), p.city, p.state, p.zip].filter(Boolean).join('_').replace(/\s+/g, '-');
  return {
    zillow: `https://www.zillow.com/homes/${dash}_rb/`,
    realtor: `https://www.realtor.com/realestateandhomes-search/${under}`,
    redfin: `https://www.google.com/search?q=${enc}+site:redfin.com`,
    homes: `https://www.google.com/search?q=${enc}+site:homes.com`,
  };
}

function rentcastHint(err) {
  if (!err) return '';
  const e = err.toLowerCase();
  if (e.includes('subscription') || e.includes('billing')) return 'Your RentCast key has no active subscription yet — add a plan (free tier available) at rentcast.io → API dashboard, then re-run. Sample ranges loaded meanwhile.';
  if (e.includes('rate') || e.includes('limit')) return 'RentCast rate limit hit — sample ranges loaded; try again shortly.';
  if (e.includes('not found') || e.includes('404')) return 'RentCast had no record for this exact address — sample ranges loaded; edit any field.';
  return 'RentCast could not be reached (' + err + ') — sample ranges loaded.';
}

Object.assign(window, { API_KEYS, getApiKey, getSettings, SETTINGS_KEY, DEFAULT_KEYS, geocode, staticMapUrl, fetchProperty, fetchValue, fetchComps, fetchRent, rentcastHint, autocomplete, floodZone, driveTime, streetViewUrl, streetViewEmbedUrl, buildListingLinks });
