# Copyright (C) all contributors <meta@public-inbox.org>
# License: AGPL-3.0+ <https://www.gnu.org/licenses/agpl-3.0.txt>

# allow searching on arbitrary headers as text
package PublicInbox::IndexHeader;
use v5.12;
use URI::Escape qw(uri_unescape);

my %T2IDX = ( # map to PublicInbox::SearchIdx methods
	phrase => 'index_phrase1',
	boolean_term => 'index_boolean_term',
	text => 'index_text1',
);

# also called by AltId->new
sub extra_indexer_new_common ($$$$) {
	my ($self, $spec, $pfx, $query) = @_;
	$pfx =~ /\A[a-z][a-z0-9]*\z/ or
		warn "W: non-word prefix in `$spec' not searchable\n";
	my %dedupe = ($pfx => undef);
	($self->{prefix}) = keys %dedupe;
	my %params = map {
		my ($k, $v) = split /=/, uri_unescape($_), 2;
		($k, $v // '');
	} split /[&;]/, $query // '';
	my $xpfx = delete($params{index_prefix}) // "X\U$pfx";
	$xpfx =~ /\A[A-Z][A-Z0-9]*\z/ or die
		die "E: `index_prefix' in `$spec' must be ALL CAPS\n";
	%dedupe = ($xpfx => undef);
	($self->{xprefix}) = keys %dedupe;
	\%params;
}

sub new {
	my ($cls, $ibx, $spec) = @_;
	my ($type, $pfx, $header, $query) = split /:/, $spec, 4;
	$pfx // die "E: `$spec' has no user prefix\n";
	$header // die "E: `$spec' has no mail header\n";
	$T2IDX{$type} // die
		"E: `$type' not supported in $spec, must be one of: ",
		join(', ', sort keys %T2IDX), "\n";
	my %dedupe = ($type => undef);
	($type) = keys %dedupe;
	%dedupe = ($header => undef);
	($header) = keys %dedupe;
	my $self = bless { header => $header, type => $type }, $cls;
	my $params = extra_indexer_new_common $self, $spec, $pfx, $query;
	$self->{hdr_method} = delete $params->{raw} ? 'header_raw' : 'header';
	my @k = keys %$params;
	warn "W: unknown params in `$spec': ", join(', ', @k), "\n" if @k;
	$self;
}

sub index_extra { # for PublicInbox::SearchIdx
	my ($self, $sidx, $eml, $mids) = @_;
	my $idx_method = $self->{-idx_method} //= $T2IDX{$self->{type}};
	my $hdr_method = $self->{hdr_method};
	for my $val ($eml->$hdr_method($self->{header})) {
		$sidx->$idx_method($self->{xprefix}, $val);
	}
}

sub user_help { # for PublicInbox::Search
	my ($self) = @_;
	($self->{prefix}, <<EOF);
the `$self->{header}' mail header  e.g. $self->{prefix}:stable
EOF
}

my %TYPE_2_QPMETHOD = (
	phrase => 'add_prefix',
	boolean_term => 'add_boolean_prefix',
	text => 'add_prefix',
);

# callback for PublicInbox::Search
sub query_parser_method { $TYPE_2_QPMETHOD{$_[0]->{type}} }

1;
