//! `GET /api/openapi.yaml` — the API contract, served verbatim (ruling 23).
//!
//! The document is hand-written and embedded; nothing renders or validates it
//! at runtime (rendering is Phase 10, external validators are dependencies we
//! refused). What keeps it honest is W10's contract suite plus the tests
//! below: every route the router serves must appear textually in the
//! document, so a route added without documentation fails the build's tests
//! rather than drifting silently.

const std = @import("std");

const http_util = @import("http_util.zig");
const router = @import("router.zig");
const server = @import("server.zig");

pub const yaml: []const u8 = @embedFile("openapi.yaml");

pub const content_type = "application/yaml";

pub fn handle(
    state: *server.WebState,
    io: std.Io,
    request: *http_util.Request,
) http_util.HandlerError!void {
    _ = state;
    _ = io;
    return http_util.respondBytes(request, .ok, yaml, content_type, &.{});
}

// ---------------------------------------------------------------------------
// tests
// ---------------------------------------------------------------------------

const testing = std.testing;

test "every served route appears textually in the document" {
    for (router.routes) |route| {
        var key_buf: [128]u8 = undefined;
        // Path keys are two-space indented under `paths:`; requiring the
        // colon keeps `/api/groups` from being satisfied by its `{id}` twin.
        const key = try std.fmt.bufPrint(&key_buf, "\n  {s}:\n", .{route.pattern});
        try testing.expect(std.mem.containsAtLeast(u8, yaml, 1, key));

        var method_buf: [16]u8 = undefined;
        const method = try std.fmt.bufPrint(&method_buf, "    {s}:\n", .{@tagName(route.method)});
        _ = std.ascii.lowerString(&method_buf, method);
        try testing.expect(std.mem.containsAtLeast(u8, yaml, 1, method_buf[0..method.len]));
    }
}

test "the document names the contract's fixed points" {
    for ([_][]const u8{
        "openapi: 3.0.3",
        "nxdns_session",
        "text/event-stream",
        "snake_case",
        "Retry-After",
    }) |needle| {
        try testing.expect(std.mem.containsAtLeast(u8, yaml, 1, needle));
    }
}
