const std = @import("std");

pub const EncodedFile = struct {
    content_type: []const u8,
    data: []const u8,
};

pub const EmbedFn = *const fn (comptime path: []const u8) []const u8;

pub fn encodeFileBase64(
    comptime embed_fn: EmbedFn,
    comptime content_type: []const u8,
    comptime path: []const u8,
) EncodedFile {
    const raw = embed_fn(path);
    const len = std.base64.standard.Encoder.calcSize(raw.len);
    var buf: [len]u8 = undefined;
    {
        @setEvalBranchQuota(1_000_000);
        _ = std.base64.standard.Encoder.encode(&buf, raw);
    }
    const final = buf;

    return .{
        .content_type = content_type,
        .data = &final,
    };
}

pub fn embedBase64Files(
    comptime embed_fn: EmbedFn,
    comptime content_type: []const u8,
    comptime extension: []const u8,
    comptime path: []const u8,
    comptime names: []const []const u8,
) type {
    var fields: [names.len]std.builtin.Type.StructField = undefined;

    for (names, 0..) |name, i| {
        const encoded = encodeFileBase64(
            embed_fn,
            content_type,
            std.fmt.comptimePrint(
                "{s}/{s}.{s}",
                .{ path, name, extension },
            ),
        );

        var name_z: [name.len:0]u8 = undefined;
        @memcpy(&name_z, name);

        fields[i] = std.builtin.Type.StructField{
            .name = &name_z,
            .type = EncodedFile,
            .is_comptime = true,
            .alignment = 0,
            .default_value_ptr = &encoded,
        };
    }

    return @Type(.{ .@"struct" = .{
        .layout = .auto,
        .is_tuple = false,
        .fields = &fields,
        .decls = &[_]std.builtin.Type.Declaration{},
    } });
}
