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

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

    // Following Zig 0.15.1 writergate changes - buffer goes in the interface
    var stderr_buffer: [1024]u8 = undefined;
    var stderr_writer = std.fs.File.stderr().writer(&stderr_buffer);
    const stderr = &stderr_writer.interface;

    const args = try std.process.argsAlloc(allocator);
    defer std.process.argsFree(allocator, args);

    // Parse command line arguments
    const config = parser.parseArgs(allocator, args) catch |err| switch (err) {
        error.HelpRequested => return,
        error.InvalidOption, error.InvalidSection, error.MultipleKeywords, error.NoKeyword => std.process.exit(1),
        else => return err,
    };

    // Display search start message
    try display.displaySearchStart(config);

    // Perform the search
    const start_time = std.time.nanoTimestamp();
    var entries = search.searchManPages(config.keyword, config.target_sections, config.show_paths, config.verbose, allocator, stderr) catch |err| {
        try stderr.print("[X] Search failed: {}\n", .{err});
        try stderr.flush(); // Don't forget to flush!
        return;
    };
    defer {
        for (entries.items) |entry| {
            // Free all the allocated strings from parseManLine
            allocator.free(entry.name);
            allocator.free(entry.section);
            allocator.free(entry.description);
            if (entry.path) |path| allocator.free(path);
        }
        entries.deinit(allocator);
    }

    // Calculate duration
    const end_time = std.time.nanoTimestamp();
    const duration_ms = @as(f64, @floatFromInt(end_time - start_time)) / 1_000_000.0;

    // Display results
    try display.displaySearchResults(entries, config, duration_ms);
}
