const std = @import("std");
const assert = std.debug.assert;
const Allocator = std.mem.Allocator;
const c = @import("c.zig");

pub const Log = opaque {
    pub fn create(
        subsystem: [:0]const u8,
        category: [:0]const u8,
    ) *Log {
        return @as(?*Log, @ptrFromInt(@intFromPtr(c.os_log_create(
            subsystem.ptr,
            category.ptr,
        )))).?;
    }

    pub fn release(self: *Log) void {
        c.os_release(self);
    }

    pub fn typeEnabled(self: *Log, typ: LogType) bool {
        return c.os_log_type_enabled(
            @ptrCast(self),
            @intFromEnum(typ),
        );
    }

    pub fn log(
        self: *Log,
        alloc: Allocator,
        typ: LogType,
        comptime format: []const u8,
        args: anytype,
    ) void {
        const str = nosuspend std.fmt.allocPrintZ(alloc, format, args) catch return;
        defer alloc.free(str);
        zig_os_log_with_type(self, typ, str.ptr);
    }

    extern "c" fn zig_os_log_with_type(*Log, LogType, [*c]const u8) void;
};

/// https://developer.apple.com/documentation/os/os_log_type_t?language=objc
pub const LogType = enum(c.os_log_type_t) {
    default = c.OS_LOG_TYPE_DEFAULT,
    debug = c.OS_LOG_TYPE_DEBUG,
    info = c.OS_LOG_TYPE_INFO,
    err = c.OS_LOG_TYPE_ERROR,
    fault = c.OS_LOG_TYPE_FAULT,
};

test {
    const testing = std.testing;

    const log = Log.create("com.mitchellh.ghostty", "test");
    defer log.release();

    try testing.expect(log.typeEnabled(.fault));
    log.log(testing.allocator, .default, "hello {d}", .{12});
}
