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

const render = @import("eink_feed_render");

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

pub const ConfigFile = struct {
    client: struct {
        id: []const u8,
        // secret: []const u8,
        auth_callback: struct {
            host: []const u8,
            port: u16,
        },
    },
    market: []const u8,
};

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.
            \\--config <str>            Path to config file.
            \\--auth <str>              Path to authorization store file.
        );

        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.config == null or
            res.args.auth == null or
            res.args.url == null or
            res.args.channel == null)
        {
            const writer = std.io.getStdErr().writer();
            try writer.writeAll("eink-feed-render-spotify\n");
            return clap.help(writer, clap.Help, &params, .{});
        }

        var config_file: std.json.Parsed(ConfigFile) = undefined;
        {
            const data = try std.fs.cwd().readFileAlloc(allocator, res.args.config.?, 1 * 1024 * 1024);
            defer allocator.free(data);
            config_file = try std.json.parseFromSlice(
                ConfigFile,
                allocator,
                data,
                .{ .allocate = .alloc_always, .ignore_unknown_fields = true },
            );
        }
        defer config_file.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 spotify_app = render.apps.Spotify.init(allocator, dim);

        var spotify = try render.api.spotify.Client.init(
            allocator,
            &.{
                .client_id = config_file.value.client.id,
                .callback_server_host = config_file.value.client.auth_callback.host,
                .callback_server_port = config_file.value.client.auth_callback.port,
                .market = config_file.value.market,
                .auth_store_file_path = res.args.auth.?,
            },
        );
        defer spotify.deinit();

        if (try spotify.restoreAuth() == null) {
            std.fs.cwd().deleteFile(spotify.auth_store_file_path) catch |err| switch (err) {
                error.FileNotFound => {},
                else => |e| return e,
            };
            _ = spotify.authorize() catch |err| {
                std.fs.cwd().deleteFile(spotify.auth_store_file_path) catch |e| switch (e) {
                    error.FileNotFound => {},
                    else => |e_inner| return e_inner,
                };
                return err;
            };
        }

        const playback_result = try spotify.getPlaybackState();
        defer playback_result.deinit();

        const png = try spotify_app.render(&playback_result.value.value);
        defer allocator.free(png);
        try feed_client.uploadFrame(
            channel.value.id,
            orientation,
            png,
            "image/png",
        );
    }
}
