module data_utils;

import handy_httpd;
import asdf;

public import handy_httpd.components.optional;


/**
 * Reads a JSON payload into a type T. Throws an `HttpStatusException` if
 * the data cannot be read or converted to the given type, with a 400 BAD
 * REQUEST status.
 * Params:
 *   ctx = The request context to read from.
 * Returns: The data that was read.
 */
T readJsonPayload(T)(ref HttpRequestContext ctx) {
    try {
        string requestBody = ctx.request.readBodyAsString();
        return deserialize!T(requestBody);
    } catch (SerdeException e) {
        import slf4d;
        warnF!"Failed to read JSON payload: %s"(e.msg);
        throw new HttpStatusException(HttpStatus.BAD_REQUEST);
    }
}

/**
 * Writes data of type T to a JSON response body. Throws an `HttpStatusException`
 * with status 501 INTERNAL SERVER ERROR if serialization fails.
 * Params:
 *   ctx = The request context to write to.
 *   data = The data to write.
 */
void writeJsonBody(T)(ref HttpRequestContext ctx, in T data) {
    import std.traits : isArray;
    try {
        static if (isArray!T) {
            if (data.length == 0) {
                ctx.response.writeBodyString("[]", "application/json");
                return;
            }
        }
        string jsonStr = serializeToJson(data);
        ctx.response.writeBodyString(jsonStr, "application/json");
    } catch (SerdeException e) {
        throw new HttpStatusException(HttpStatus.INTERNAL_SERVER_ERROR);
    }
}

ulong getUnixTimestampMillis() {
  import std.datetime;
  SysTime now = Clock.currTime();
  SysTime unixEpoch = SysTime(DateTime(1970, 1, 1), UTC());
  Duration diff = now - unixEpoch;
  return diff.total!"msecs";
}