<cfsetting showdebugoutput="false">
<cfsetting enablecfoutputonly="true">

<cfcontent type="application/json; charset=utf-8" reset="true">
<cfheader name="Cache-Control" value="no-store">

<cfscript>
// Read JSON body for user location
function readJsonBody() {
  var raw = getHttpRequestData().content;
  if (isNull(raw) OR len(trim(raw)) EQ 0) return {};
  try {
    var data = deserializeJSON(raw);
    if (isStruct(data)) return data;
    return {};
  } catch (any e) {
    return {};
  }
}

// Haversine formula to calculate distance in miles
function haversineDistance(lat1, lng1, lat2, lng2) {
  var R = 3959; // Earth radius in miles
  var dLat = (lat2 - lat1) * 3.14159265359 / 180;
  var dLng = (lng2 - lng1) * 3.14159265359 / 180;
  var a = sin(dLat/2) * sin(dLat/2) +
          cos(lat1 * 3.14159265359 / 180) * cos(lat2 * 3.14159265359 / 180) *
          sin(dLng/2) * sin(dLng/2);
  // Clamp a to avoid NaN from sqrt of negative or division by zero
  if (a < 0) a = 0;
  if (a > 1) a = 1;
  var c = 2 * asin(sqr(a));
  return R * c;
}

try {
  data = readJsonBody();
  userLat = structKeyExists(data, "lat") ? val(data.lat) : 0;
  userLng = structKeyExists(data, "lng") ? val(data.lng) : 0;
  hasUserLocation = (userLat != 0 AND userLng != 0);

  // Get businesses with their address coordinates (exclude demo and private)
  q = queryExecute(
    "
      SELECT
        b.ID,
        b.Name,
        a.Latitude AS AddressLat,
        a.Longitude AS AddressLng,
        a.City AS AddressCity,
        a.Line1 AS AddressLine1
      FROM Businesses b
      LEFT JOIN Addresses a ON b.AddressID = a.ID
      WHERE (b.IsDemo = 0 OR b.IsDemo IS NULL)
        AND (b.IsPrivate = 0 OR b.IsPrivate IS NULL)
      ORDER BY b.Name
    ",
    [],
    { datasource = "payfrit" }
  );

  // Convert query -> array of structs with distance
  rows = [];
  for (i = 1; i <= q.recordCount; i++) {
    row = {
      "BusinessID": q.ID[i],
      "Name": q.Name[i],
      "City": isNull(q.AddressCity[i]) ? "" : q.AddressCity[i],
      "Line1": isNull(q.AddressLine1[i]) ? "" : q.AddressLine1[i]
    };

    // Calculate distance if we have both user location and business location
    bizLat = isNull(q.AddressLat[i]) ? 0 : val(q.AddressLat[i]);
    bizLng = isNull(q.AddressLng[i]) ? 0 : val(q.AddressLng[i]);

    if (hasUserLocation AND bizLat != 0 AND bizLng != 0) {
      row["DistanceMiles"] = haversineDistance(userLat, userLng, bizLat, bizLng);
    } else {
      row["DistanceMiles"] = 99999; // No location = sort to end
    }

    arrayAppend(rows, row);
  }

  // Sort by distance if user location provided
  if (hasUserLocation) {
    arraySort(rows, function(a, b) {
      return compare(a.DistanceMiles, b.DistanceMiles);
    });
  }

  // Limit to 20 nearest restaurants
  if (arrayLen(rows) > 20) {
    rows = arraySlice(rows, 1, 20);
  }

  // Provide BOTH keys to satisfy any Flutter casing expectation
  try{logPerf(0);}catch(any e){}
  writeOutput(serializeJSON({
    "OK": true,
    "ERROR": "",
    "VERSION": "businesses_list_v5",
    "BUSINESSES": rows,
    "Businesses": rows
  }));
  abort;

} catch (any e) {
  apiAbort({
    "OK": false,
    "ERROR": "server_error",
    "DETAIL": e.message
  });
}
</cfscript>
