-- encode straeto API params into the query string by the graphql API.
-- yes, javascript in the database: the lazy way.
CREATE OR REPLACE FUNCTION encode_straeto_querystring(obj jsonb) RETURNS text
LANGUAGE plv8 STRICT IMMUTABLE AS $$
  return Object.keys(obj).map(function(variableName) {
    const variableValue = obj[variableName];
    if (typeof variableValue == 'object') {
      return encodeURIComponent(variableName) + '=' + encodeURIComponent(JSON.stringify(variableValue));
    } else {
      return encodeURIComponent(variableName) + '=' + encodeURIComponent(variableValue);
    }
  }).join('&');
$$;

CREATE OR REPLACE FUNCTION create_straeto_parameters(bus_routes text[]) RETURNS jsonb
LANGUAGE plpgsql AS $$
  DECLARE query_params jsonb;
  BEGIN
    -- This is the unencoded GraphQL request payload.
    query_params := '{
      "operationName": "BusLocationByRoute",
      "variables": { "trips":[], "routes": [] },
      "extensions": {
        "persistedQuery": {
          "version": 1,
          "sha256Hash": "8f9ee84171961f8a3b9a9d1a7b2a7ac49e7e122e1ba1727e75cfe3a94ff3edb8"
        }
      }
    }'::jsonb;

    -- Add requested bus routes to the `routes` GraphQL variable.
    SELECT INTO query_params
		jsonb_set(query_params, '{variables, routes}', array_to_json(bus_routes)::jsonb);
    RETURN query_params;
  END
$$;

-- Builds the full request URL to download bus positions of the given
-- route numbers.
CREATE OR REPLACE FUNCTION build_api_url(bus_routes text[]) RETURNS text LANGUAGE sql AS $$
  SELECT concat(
    'https://straeto.is/graphql?',
    encode_straeto_querystring(create_straeto_parameters(bus_routes))
  );
$$;

-- Called by a scheduled job to request data on a timer. A trigger
-- handles insertion of the response after record initially inserted.
CREATE TABLE IF NOT EXISTS raw_bus_position_requests(
  request_id int,
  created TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT NOW()
);

CREATE OR REPLACE FUNCTION gather_bus_data()
RETURNS void LANGUAGE sql
as $$
  INSERT INTO raw_bus_position_requests (request_id) SELECT
  net.http_get(
    url := build_api_url(array['1', '2', '3']),
    headers := '{"Content-Type": "application/json"}'::jsonb
  );
$$;
