const std = @import("std");
const builtin = @import("builtin");
const clap = @import("clap");
const zdt = @import("zdt");

const render = @import("eink_feed_render");

pub const std_options: std.Options = .{
    .log_level = if (builtin.mode == .Debug) .debug else .info,
};

pub fn main() !void {
    var gpa = std.heap.GeneralPurposeAllocator(.{
        .thread_safe = true,
    }){};
    defer _ = gpa.deinit();
    const allocator = gpa.allocator();

    {
        const params = comptime clap.parseParamsComptime(
            \\-h, --help            Display this help and exit.
            \\--url <str>           URL of eink-feed server.
            \\--channel <u32>       Channel ID.
            \\--efa <str>           URL of EFA server.
            \\--stop <str>          Stop ID.
            \\--tz <str>            Time zone.
            \\--max <usize>         Max number of departures listed.
            \\--show-operator       Show operator.
            \\--stopfinder <str>    Search for stops on the EFA server with the given search query.
        );

        var diag = clap.Diagnostic{};
        var res = clap.parse(clap.Help, &params, clap.parsers.default, .{
            .diagnostic = &diag,
            .allocator = allocator,
        }) catch |err| {
            diag.report(std.io.getStdErr().writer(), err) catch {};
            return err;
        };
        defer res.deinit();

        if (res.args.help != 0 or
            res.args.efa == null or
            ((res.args.stop == null or
                res.args.tz == null or
                res.args.url == null or
                res.args.channel == null) and
                res.args.stopfinder == null))
        {
            const writer = std.io.getStdErr().writer();
            try writer.writeAll("eink-feed-render-departures\n");
            return clap.help(writer, clap.Help, &params, .{});
        }

        const efa = try render.api.efa.Client.init(allocator, res.args.efa.?);
        defer efa.deinit();

        if (res.args.stopfinder) |query| {
            try efa.findStops(query);
            return;
        }

        var tz = try zdt.Timezone.fromTzdata(res.args.tz.?, allocator);
        defer tz.deinit();

        render.renderer.init();
        defer render.renderer.deinit();

        const feed_client = try render.FeedClient.init(allocator, res.args.url.?);
        defer feed_client.deinit();

        const channel = try feed_client.getChannel(res.args.channel.?);
        defer channel.deinit();
        const dim = render.Dimensions{
            .width = channel.value.display.width,
            .height = channel.value.display.height,
        };
        const orientation = channel.value.display.orientation.toInternal();
        const departures = render.apps.Departures.init(allocator, dim);

        const stop_id: []const u8 = res.args.stop.?;

        const now = try zdt.Datetime.now(.{ .tz = &tz });
        const efa_departures = try efa.getDepartures(stop_id);
        defer efa_departures.deinit();

        const png = try departures.render(&efa_departures.value, .{
            .now = &now,
            .tz = &tz,
            .max_items = res.args.max orelse 15,
            .show_operator = res.args.@"show-operator" != 0,
        });
        defer allocator.free(png);
        try feed_client.uploadFrame(
            channel.value.id,
            orientation,
            png,
            "image/png",
        );
    }
}
