const std = @import("std");
const types = @import("types.zig");

// Following Zig 0.15.1 writergate changes - buffer goes in the interface
var stdout_buffer: [4096]u8 = undefined;
var stdout_writer = std.fs.File.stdout().writer(&stdout_buffer);
const stdout = &stdout_writer.interface;

pub fn displayManEntry(entry: types.ManEntry) !void {
    try stdout.print("{s} {s}({s}) - {s}\n", .{ entry.getSectionMarker(), entry.name, entry.section, entry.description });
    if (entry.path) |path| {
        try stdout.print("    -> {s}\n", .{path});
    }
    // Don't forget to flush! - per writergate guidelines
    try stdout.flush();
}

pub fn displaySearchResults(
    entries: types.ManEntryList,
    config: types.SearchConfig,
    duration_ms: f64,
) !void {
    if (config.verbose) {
        if (config.target_sections) |sections| {
            // e.g., join sections for display
            var joined: [32]u8 = undefined;
            var pos: usize = 0;
            for (sections, 0..) |s, i| {
                if (i != 0) {
                    joined[pos] = ',';
                    pos += 1;
                }
                // Copy the string into the buffer
                @memcpy(joined[pos .. pos + s.len], s);
                pos += s.len;
            }
            try stdout.print(
                "[=] Found {d} entries matching '{s}' in section(s) {s}\n",
                .{ entries.items.len, config.keyword, joined[0..pos] },
            );
            try stdout.print("[=] Found {d} entries matching '{s}'\n", .{ entries.items.len, config.keyword });
        }
        try stdout.print("\n", .{});
    } else {
        if (config.target_sections) |sections| {
            // Join sections for display
            var joined: [32]u8 = undefined;
            var pos: usize = 0;
            for (sections, 0..) |s, i| {
                if (i != 0) {
                    joined[pos] = ',';
                    pos += 1;
                }
                @memcpy(joined[pos .. pos + s.len], s);
                pos += s.len;
            }
            try stdout.print("[=] Found {d} entries matching '{s}' in section {s}\n\n", .{ entries.items.len, config.keyword, joined[0..pos] });
        } else {
            try stdout.print("[=] Found {d} entries matching '{s}'\n\n", .{ entries.items.len, config.keyword });
        }
    }
    try stdout.flush(); // Flush header

    // Iterate over entries
    for (entries.items) |entry| {
        try displayManEntry(entry);
    }

    if (config.verbose) {
        try stdout.print("───────────────────────────────────────────────\n", .{});
        try stdout.print("[=] Completed in {d:.1}ms\n", .{duration_ms});
        try stdout.flush(); // Flush footer
    }
}

pub fn displaySearchStart(config: types.SearchConfig) !void {
    if (config.verbose) {
        if (config.target_sections) |sections| {
            // Join sections for display (same pattern as displaySearchResults)
            var joined: [32]u8 = undefined;
            var pos: usize = 0;
            for (sections, 0..) |s, i| {
                if (i != 0) {
                    joined[pos] = ',';
                    pos += 1;
                }
                @memcpy(joined[pos .. pos + s.len], s);
                pos += s.len;
            }
            try stdout.print("[=] Searching for '{s}' in man pages database (section {s})...\n", .{ config.keyword, joined[0..pos] });
        } else {
            try stdout.print("[=] Searching for '{s}' in man pages database...\n", .{config.keyword});
        }
        try stdout.flush(); // Flush search start message
    }
}

// ============================================================================
// TESTS
// ============================================================================

test "displayManEntry - basic entry" {
    const entry = types.ManEntry{
        .name = "ls",
        .section = "1",
        .description = "list directory contents",
        .path = null,
    };
    // Verify function doesn't panic
    try displayManEntry(entry);
}

test "displaySearchResults - non-verbose no sections" {
    var gpa = std.heap.GeneralPurposeAllocator(.{}){};
    defer _ = gpa.deinit();
    const allocator = gpa.allocator();

    var entries = types.ManEntryList.init(allocator);
    defer {
        for (entries.items) |entry| {
            allocator.free(entry.name);
            allocator.free(entry.section);
            allocator.free(entry.description);
        }
        entries.deinit();
    }

    try entries.append(types.ManEntry{
        .name = try allocator.dupe(u8, "ls"),
        .section = try allocator.dupe(u8, "1"),
        .description = try allocator.dupe(u8, "list files"),
        .path = null,
    });

    const config = types.SearchConfig{
        .keyword = "ls",
        .target_sections = null,
        .show_paths = false,
        .verbose = false,
    };

    try displaySearchResults(entries, config, 100.0);
}

test "displaySearchStart - non-verbose" {
    const config = types.SearchConfig{
        .keyword = "test",
        .target_sections = null,
        .show_paths = false,
        .verbose = false,
    };
    // Should not output anything in non-verbose mode
    try displaySearchStart(config);
}

test "displaySearchStart - verbose" {
    const config = types.SearchConfig{
        .keyword = "sleep",
        .target_sections = null,
        .show_paths = false,
        .verbose = true,
    };
    try displaySearchStart(config);
}
