# OpenSearch::Client is an unofficial client for OpenSearch. 
# It is derived from Search::Elasticsearch version 7.714
# License details from the original work are contained in the
# NOTICE file distributed with this work.
#
#-----------------------------------------------------------------------
# OpenSearch::Client
#-----------------------------------------------------------------------
# Copyright 2026 Mark Dootson
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.


package MockCxn;

use strict;
use warnings;

our $VERSION = $OpenSearch::Client::VERSION;

use Data::Dumper;
use Moo;
with 'OpenSearch::Client::Role::Cxn', 'OpenSearch::Client::Role::Is_Sync';

use Sub::Exporter -setup => {
    exports => [ qw(
            mock_static_client
            mock_sniff_client
            mock_noping_client
            )
    ]
};

our $i = 0;

has 'mock_responses' => ( is => 'rw', required => 1 );
has 'marked_live'    => ( is => 'rw', default  => sub {0} );
has 'node_num'       => ( is => 'ro', default  => sub { ++$i } );

#===================================
sub BUILD {
#===================================
    my $self = shift;
    $self->logger->debugf( "[%s-%s] CREATED", $self->node_num, $self->host );
}

#===================================
sub error_from_text { return $_[2] }
#===================================

#===================================
sub perform_request {
#===================================
    my $self = shift;

    my $params   = shift;
    my $response = shift @{ $self->mock_responses }
        or die "Mock responses exhausted";

    if ( my $node = $response->{node} ) {
        die "Mock response handled by wrong node ["
            . $self->node_num . "]: "
            . Dumper($response)
            unless $node eq $self->node_num;
    }

    my $log_msg;

    # Sniff request
    if ( my $nodes = $response->{sniff} ) {
        $log_msg = "SNIFF: [" . ( join ", ", @$nodes ) . "]";
        $response->{code} ||= 200;
        my $i = 1;
        unless ( $response->{error} ) {
            $response->{content} = $self->serializer->encode(
                {   nodes => {
                        map {
                            'node_'
                                . $i++ => { http_address => "inet[/$_]" }
                        } @$nodes
                    }
                }
            );
        }
    }

    # Normal request
    elsif ( $response->{code} ) {
        $log_msg = "REQUEST: " . ( $response->{error} || $response->{code} );
    }

    # Ping request
    else {
        $log_msg = "PING: " . ( $response->{ping} ? 'OK' : 'NOT_OK' );
        $response
            = $response->{ping}
            ? { code => 200 }
            : { code => 500, error => 'Cxn' };
    }

    $self->logger->debugf( "[%s-%s] %s", $self->node_num, $self->host,
        $log_msg );

    return $self->process_response(
        $params,                 # request
        $response->{code},       # code
        $response->{error},      # msg
        $response->{content},    # body
        { 'content-type' => 'application/json' }
    );
}

#### EXPORTS ###

my $trace
    = !$ENV{TRACE}       ? undef
    : $ENV{TRACE} eq '1' ? 'Stderr'
    :                      [ 'File', $ENV{TRACE} ];

#===================================
sub mock_static_client { _mock_client( 'Static',         @_ ) }
sub mock_sniff_client  { _mock_client( 'Sniff',          @_ ) }
sub mock_noping_client { _mock_client( 'Static::NoPing', @_ ) }
#===================================

#===================================
sub _mock_client {
#===================================
    my $pool   = shift;
    my $params = shift;
    $i = 0;
    return OpenSearch::Client->new(
        cxn            => '+MockCxn',
        cxn_pool       => $pool,
        mock_responses => \@_,
        randomize_cxns => 0,
        log_to         => $trace,
        %$params,
    )->transport;
}

1
