package PGSM;

use File::Basename;
use File::Compare;
use Test::More;

our @ISA = qw( Exporter );

# These CAN be exported.
our @EXPORT =
  qw( pgsm_init_pg pgsm_start_pg pgsm_stop_pg pgsm_psql_cmd pgsm_setup_pg_stat_monitor pgsm_create_extension pgsm_reset_pg_stat_monitor pgsm_drop_extension );

# Instance of pg server that would be spanwed by TAP testing. A new server will be created for each TAP test.
our $pg_node;

# Expected .out filename of TAP testcase being executed. These are already part of repo under t/expected/*.
our $expected_filename_with_path;

# Major version of PG Server that we are using.
our $PG_MAJOR_VERSION;

# Result .out filename of TAP testcase being executed. Where needed, a new *.out will be created for each TAP test.
our $out_filename_with_path;

# Runtime output file that is used only for debugging purposes for comparison to PGSS, blocks and timings.
our $debug_out_filename_with_path;

BEGIN
{
	# Get PG Server Major version from pg_config
	`pg_config --version` =~ /^[^ ]+ (\d+)/;
	$PG_MAJOR_VERSION = $1;

	# Depending upon PG server version load the required module at runtime when pgsm.pm is loaded.
	my $node_module =
	  $PG_MAJOR_VERSION > 14 ? "PostgreSQL::Test::Cluster" : "PostgresNode";
	my $node_module_file = $node_module;
	$node_module_file =~ s[::][/]g;
	$node_module_file .= '.pm';
	require $node_module_file;
	$node_module->import;
}

sub pgsm_init_pg
{
	print "Postgres major version: $PG_MAJOR_VERSION \n";

	# For Server version 15 & above, spawn the server using PostgreSQL::Test::Cluster
	if ($PG_MAJOR_VERSION > 14)
	{
		$pg_node = PostgreSQL::Test::Cluster->new('pgsm_regression');
	}
	# For Server version 14 & below, spawn the server using PostgresNode
	else
	{
		$pg_node = PostgresNode->get_new_node('pgsm_regression');
	}

	$pg_node->dump_info;
	$pg_node->init(extra => ['--lc-collate=C']);
	return $pg_node;
}

sub append_to_file
{
	my ($str) = @_;

	# For Server version 15 & above, use PostgreSQL::Test::Utils to write to files
	if ($PG_MAJOR_VERSION > 14)
	{
		PostgreSQL::Test::Utils::append_to_file($out_filename_with_path,
			$str . "\n");
	}
	# For Server version 14 & below, use PostgresNode to write to files
	else
	{
		TestLib::append_to_file($out_filename_with_path, $str . "\n");
	}
	chmod(0640, $out_filename_with_path)
	  or die("unable to set permissions for $out_filename_with_path");

	return;
}

sub append_to_debug_file
{
	my ($str) = @_;

	# For Server version 15 & above, use PostgreSQL::Test::Utils to write to files
	if ($PG_MAJOR_VERSION > 14)
	{
		PostgreSQL::Test::Utils::append_to_file($debug_out_filename_with_path,
			$str . "\n");
	}
	# For Server version 14 & below, use PostgresNode to write to files
	else
	{
		TestLib::append_to_file($debug_out_filename_with_path, $str . "\n");
	}
	chmod(0640, $debug_out_filename_with_path)
	  or die("unable to set permissions for $debug_out_filename_with_path");

	return;
}

sub setup_files_dir
{
	my ($perlfilename) = @_;

	# Expected folder where expected output will be present
	my $expected_folder = "t/expected";

	# Results/out folder where generated results files will be placed
	my $results_folder = "t/results";

	# Check if results folder exists or not, create if it doesn't
	unless (-d $results_folder)
	{
		mkdir $results_folder
		  or die "Can't create folder $results_folder: $!\n";
	}

	# Check if expected folder exists or not, bail out if it doesn't
	unless (-d $expected_folder)
	{
		BAIL_OUT "Expected files folder $expected_folder doesn't exist: \n";
	}

	# Remove .pl from filename and store in a variable
	my @split_arr = split /\./, $perlfilename;

	my $filename_without_extension = $split_arr[0];

	# Create expected filename with path
	my $expected_filename = "${filename_without_extension}.out";

	if ($filename_without_extension eq
		"007_settings_pgsm_query_shared_buffer")
	{
		$expected_filename .= ".$PG_MAJOR_VERSION";
	}

	$expected_filename_with_path = "${expected_folder}/${expected_filename}";

	# Create results filename with path
	my $out_filename = "${filename_without_extension}.out";
	$out_filename_with_path = "${results_folder}/${out_filename}";

	# Delete already existing result out file, if it exists.
	if (-f $out_filename_with_path)
	{
		unlink($out_filename_with_path)
		  or die
		  "Can't delete already existing $out_filename_with_path: $!\n";
	}

	$debug_out_filename_with_path = "${results_folder}/${out_filename}.debug";
}

sub compare_results
{
	# Compare expected and results files and return the result
	return compare($expected_filename_with_path, $out_filename_with_path);
}

1;
