# $Id$
# Filefind robot for HPT
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# By Jay Harris (1:229/664) in 2025 with lots of help from ChatGPT
#
# BEGIN {
#   require "filefind.pl";
# }
#
# sub filter {
#   &filefind;
# }
#
# Generate an allfiles list with htick
# (e.g. htick filelist /home/fido/ALLFILES.TXT) and set
# $allfiles_path accordingly.

use POSIX qw(strftime);

#=======================================================#
# FILEFIND SUBROUTINE
#=======================================================#
sub filefind {
    my @myaddr = @{ $config{addr} };
    if ($DEBUG_MODE) {
        w_log('1', "filefind.pl: begin [$area]");
    }

    #== CONFIGURATION ==#

    my $myname          = "Filefind Robot";
    my $report_subj     = "Re: $subject";
    my $allfiles_path   = "/home/ubuntu/fido/binkd/ALLFILES.TXT"; # File to search
    my $report_tearline = "filefind.pl";
    my $header          = "FREQ filename or download from https://hub.nrbbs.net";
    my $mosem           = "/home/ubuntu/fido/semaphore/mail.out"; # Create semaphore for outgoing mail

    # Echo area(s) to monitor with address (case-sensitive)
    my %area_addr = (
        "MIN_FILEFIND" => "618:400/1",
        "FILEFIND"     => "1:229/664",
    );

    # Default origin line
    my $default_origin = "$myname: HPT-perl hook";

    # Custom origin line per zone
    my %zone_origin = (
        "1"   => "Northern Realms",
        "618" => "Net 400 Hub Eh?",
    );

    # Ignore file find requests from these names (case-insensitive)
    my @ignore_from_regexp = (
        'allfix',
        'filefind',
    );
    #== END CONFIGURATION ==#

    # Set address
    my $myaddr = $area_addr{$area} // $myaddr[0];

    # Only check configured areas
    return "" unless exists $area_addr{$area};    

    # Only respond to messages addressed to "Filefind" or "Allfix" (case-insensitive)
    return "" unless uc($toname) eq "FILEFIND" || uc($toname) eq "ALLFIX";

    # Ignore requests from specified names
    foreach my $ignore_from (@ignore_from_regexp) {
        return "" if ($fromname =~ /$ignore_from/i);
    }

    # Determine zone of message area
    my ($areazone) = $area_addr{$area} =~ /^(\d+):/;

    # Select the proper origin line
    my $report_origin = $zone_origin{$areazone} || $default_origin;

    my $query = $subject;
    $query =~ s{^[/%]}{};     # Remove leading slash or percent if present
    $query =~ s/["']//g;      # Strip all quotes
    $query =~ s/^\s+|\s+$//g; # Strip leading/trailing whitespace
    return "" if ($query eq "");

    w_log('C', "filefind.pl: Processing request for '$query' from $fromname ($fromaddr)");

    #---------------------------------------------------
    # SEARCH FILE
    #---------------------------------------------------
    my @results = search_filelist($query, $allfiles_path);
    return "" unless @results; # Do not reply if no results

    my $reply_body = join("", @results);

    #---------------------------------------------------
    # BUILD REPLY MESSAGE
    #---------------------------------------------------
    my $msgtext = "Filefind result for: $query\r\r" . $reply_body;

    # Get sender's MSGID (if any) for REPLY kludge
    if ( $text =~ /\r\x01MSGID:\s*(.*?)\r/ ) {
        $rply = $1;
    }

    # Prepend kludges
    my $mid = `gnmsgid`;
    chomp $mid;
    my $tz = strftime("%z", localtime());
    $tz =~ s/^\+//;

    $msgtext = "\x01MSGID: $myaddr $mid\r";
    $msgtext .= ($rply ? "\x01REPLY: $rply\r" : "");
    $msgtext .= "\x01TZUTC: $tz\r\x01CHRS: CP437 2\r";
    $msgtext .= "Filefind result for: $query\r\r$header\r\r$reply_body";
    $msgtext .= "--- $report_tearline\r * Origin: $report_origin ($myaddr)\r";

    putMsgInArea($area, $myname, $fromname, $myaddr, $myaddr, $report_subj, '', "Uns Loc", $msgtext, 3);
    w_log('E', "filefind.pl: Responding to request in [$area].");

    unless (open FILE, '>' . $mosem) { die "\nUnable to create $mosem\n"; }
    close FILE;

    return '';
}

#=======================================================#
# SEARCH LOGIC
#=======================================================#
sub search_filelist {
    my ($query, $allfiles_path) = @_;
    my @results;
    my $in_block = 0;
    my $current_header = "";
    my @block_lines = ();

    open(my $fh, "<", $allfiles_path) or return ("Unable to read ALLFILES.TXT\r");

    while (my $line = <$fh>) {
        chomp $line;

        # truncate to 77 chars
        $line = substr($line, 0, 77);

        # ----- Start of a new block -----
        if ($line =~ /^FileArea:/) {
            # Process previous block before starting a new one
            if (@block_lines) {
                push @results, process_block($query, $current_header, \@block_lines);
            }

            # Start a new block
            $current_header = $line;
            @block_lines = ();
            $in_block = 1;
            next;
        }

        # If not in a block, skip
        next unless $in_block;

        # Skip footer lines
        next if $line =~ /^Total files in area:/;

        # Skip separator lines
        next if $line =~ /^-+$/;

        # Store clean block content
        push @block_lines, $line;
    }

    # Process final block
    if (@block_lines) {
        push @results, process_block($query, $current_header, \@block_lines);
    }

    close $fh;

    # Flatten results
    return grep { $_ ne '' } @results;
}

# --------- helper: process a single FileArea block ---------
sub process_block {
    my ($query, $header, $lines_ref) = @_;
    my @lines = @$lines_ref;
    my @out;

    # Flatten entries: first line of file + following indented lines
    my @entries;
    my @current_entry;
    foreach my $line (@lines) {
        if ($line =~ /^\S/) {
            # non-indented = start of new entry
            if (@current_entry) { push @entries, [@current_entry]; }
            @current_entry = ($line);
        } else {
            # indented = continuation of previous line
            push @current_entry, $line;
        }
    }
    push @entries, [@current_entry] if @current_entry;

    # Check which entries match query
    my @matched_entries;
    foreach my $entry_ref (@entries) {
        my $entry_text = join(" ", @$entry_ref);  # join lines to search easily
        if ($entry_text =~ /\Q$query\E/i) {
            push @matched_entries, $entry_ref;
        }
    }

    return () unless @matched_entries;  # nothing to return

    # Build output
    push @out, "$header\r";
    push @out, "-----------------------------------------------------------------------------\r";

    foreach my $entry_ref (@matched_entries) {
        push @out, map { "$_\r" } @$entry_ref;
    }

    push @out, "\r";
    return @out;
}

w_log('U', 'filefind.pl is LOADED');
1;
