const std = @import("std");
const vaxis = @import("vaxis");
const Cell = vaxis.Cell;
const TextInput = vaxis.widgets.TextInput;

const log = std.log.scoped(.main);
pub fn main() !void {
    var gpa = std.heap.GeneralPurposeAllocator(.{}){};
    defer {
        const deinit_status = gpa.deinit();
        if (deinit_status == .leak) {
            log.err("memory leak", .{});
        }
    }
    const alloc = gpa.allocator();

    var tty = try vaxis.Tty.init();
    defer tty.deinit();

    var vx = try vaxis.init(alloc, .{});
    defer vx.deinit(alloc, tty.anyWriter());

    var loop: vaxis.Loop(Event) = .{ .tty = &tty, .vaxis = &vx };
    try loop.init();

    try loop.start();
    defer loop.stop();

    try vx.queryTerminal(tty.anyWriter(), 1 * std.time.ns_per_s);

    var text_input = TextInput.init(alloc, &vx.unicode);
    defer text_input.deinit();

    var selected_option: ?usize = null;

    const options = [_][]const u8{
        "option 1",
        "option 2",
        "option 3",
    };

    // The main event loop. Vaxis provides a thread safe, blocking, buffered
    // queue which can serve as the primary event queue for an application
    while (true) {
        // nextEvent blocks until an event is in the queue
        const event = loop.nextEvent();
        // exhaustive switching ftw. Vaxis will send events if your Event
        // enum has the fields for those events (ie "key_press", "winsize")
        switch (event) {
            .key_press => |key| {
                if (key.codepoint == 'c' and key.mods.ctrl) {
                    break;
                } else if (key.matches(vaxis.Key.tab, .{})) {
                    if (selected_option == null) {
                        selected_option = 0;
                    } else {
                        selected_option.? = @min(options.len - 1, selected_option.? + 1);
                    }
                } else if (key.matches(vaxis.Key.tab, .{ .shift = true })) {
                    if (selected_option == null) {
                        selected_option = 0;
                    } else {
                        selected_option.? = selected_option.? -| 1;
                    }
                } else if (key.matches(vaxis.Key.enter, .{})) {
                    if (selected_option) |i| {
                        log.err("enter", .{});
                        try text_input.insertSliceAtCursor(options[i]);
                        selected_option = null;
                    }
                } else {
                    if (selected_option == null)
                        try text_input.update(.{ .key_press = key });
                }
            },
            .winsize => |ws| {
                try vx.resize(alloc, tty.anyWriter(), ws);
            },
            else => {},
        }

        const win = vx.window();
        win.clear();

        text_input.draw(win);

        if (selected_option) |i| {
            win.hideCursor();
            for (options, 0..) |opt, j| {
                log.err("i = {d}, j = {d}, opt = {s}", .{ i, j, opt });
                var seg = [_]vaxis.Segment{.{
                    .text = opt,
                    .style = if (j == i) .{ .reverse = true } else .{},
                }};
                _ = win.print(&seg, .{ .row_offset = @intCast(j + 1) });
            }
        }
        try vx.render(tty.anyWriter());
    }
}

// Our Event. This can contain internal events as well as Vaxis events.
// Internal events can be posted into the same queue as vaxis events to allow
// for a single event loop with exhaustive switching. Booya
const Event = union(enum) {
    key_press: vaxis.Key,
    winsize: vaxis.Winsize,
    focus_in,
    foo: u8,
};
