use strict;
use warnings;
use File::Basename qw(basename dirname);
use File::Compare;
use File::Path qw(rmtree);

use PostgreSQL::Test::Cluster;
use PostgreSQL::Test::Utils;
use Test::More;

# Set umask so test directories and files are created with default permissions
umask(0077);

my $tempdir = PostgreSQL::Test::Utils::tempdir;
my $basebackupdir = $tempdir . '/basebackup';
my $basebackupdir2 = $tempdir . '/basebackup2';
my $archivedir =  $tempdir . '/archive';

my $primary = PostgreSQL::Test::Cluster->new('primary');
my $replica = PostgreSQL::Test::Cluster->new('replica');

# Initialize primary
$primary->init(allows_streaming => 1, extra => ['--data-checksums']);
$primary->append_conf("postgresql.conf", "archive_mode = 'on'");
$primary->append_conf("postgresql.conf", "archive_command = 'cp -rv %p $archivedir/'");
$primary->start;

# Initialize replica
$replica->init(extra => ['--data-checksums']);

my $primary_pgdata = $primary->data_dir;
my $replica_pgdata = $replica->data_dir;
my $replica_port = $replica->port;

mkdir($basebackupdir);
mkdir($basebackupdir2);
mkdir($archivedir);

$primary->safe_psql('postgres', 'CREATE DATABASE test_db');
$primary->safe_psql('test_db', 'CREATE TABLE test as select generate_series(1,10)');
$primary->safe_psql('postgres', 'CREATE ROLE postgres WITH LOGIN REPLICATION');

$primary->command_ok([ 'pg_basebackup', '-D', "$basebackupdir", '-p', $primary->port, '--verbose' ],
	'pg_basebackup runs');
ok(-f "$basebackupdir/PG_VERSION", 'backup was created');

$primary->safe_psql('test_db', "SELECT pg_create_restore_point('rp_repl_bug')");
$primary->stop('smart');

# apply base backup to generate the second timeline from the first (1 -> 2)
$primary->command_ok([ 'rm', '-rf', $primary_pgdata ],
	'first rm primary pgdata');
$primary->command_ok([ 'cp', '-r', $basebackupdir, $primary_pgdata ],
	'first copy basebackup to primary');
# configure recovery
$primary->set_recovery_mode;
open my $conf, '>', "$primary_pgdata/postgresql.auto.conf";
print $conf "synchronous_standby_names = '*'\n";
print $conf "recovery_target_action = 'promote'\n";
print $conf "restore_command = 'cp -vr $archivedir/%f $primary_pgdata/%p'\n";
print $conf "recovery_target_name = 'rp_repl_bug'\n";
close $conf;
$primary->start;

$primary->safe_psql('test_db', "SELECT pg_switch_wal()");

$primary->command_ok([ 'pg_basebackup', '-D', "$basebackupdir2", '-p', $primary->port, '--verbose' ],
	'second pg_basebackup runs');
ok(-f "$basebackupdir2/PG_VERSION", 'backup was created');

$primary->safe_psql('test_db', "SELECT pg_create_restore_point('rp_repl_bug2')");
$primary->stop('smart');

# apply base backup to generate the third timeline from the second (2 -> 3)
$primary->command_ok([ 'rm', '-rf', $primary_pgdata ],
	'second rm primary pgdata');
$primary->command_ok([ 'cp', '-r', $basebackupdir2, $primary_pgdata ],
	'second copy basebackup to primary');
# configure recovery
$primary->set_recovery_mode;
open $conf, '>', "$primary_pgdata/postgresql.auto.conf";
print $conf "synchronous_standby_names = '*'\n";
print $conf "recovery_target_action = 'promote'\n";
print $conf "restore_command = 'cp -vr $archivedir/%f $primary_pgdata/%p'\n";
print $conf "recovery_target_name = 'rp_repl_bug2'\n";
close $conf;
$primary->start;

$primary->safe_psql('test_db', "SELECT pg_switch_wal()");
$primary->stop('smart');

# apply base backup to generate the fourth timeline from the first (1 -> 4)
$primary->command_ok([ 'rm', '-rf', $primary_pgdata ],
	'second rm primary pgdata');
$primary->command_ok([ 'cp', '-r', $basebackupdir, $primary_pgdata ],
	'second copy basebackup to primary');
# configure recovery
$primary->set_recovery_mode;
open $conf, '>', "$primary_pgdata/postgresql.auto.conf";
print $conf "synchronous_standby_names = '*'\n";
print $conf "recovery_target_action = 'promote'\n";
print $conf "restore_command = 'cp -vr $archivedir/%f $primary_pgdata/%p'\n";
print $conf "recovery_target_name = 'rp_repl_bug'\n";
close $conf;
$primary->start;

$primary->safe_psql('test_db', "SELECT pg_create_physical_replication_slot('internal_wal_replication_slot')");

# configure replica to recovery
$replica->command_ok([ 'rm', '-rf', $replica_pgdata ],
	'rm replica pgdata');
$replica->command_ok([ 'cp', '-r', $basebackupdir, $replica_pgdata ],
	'copy basebackup to replica');

$replica->set_recovery_mode;
open $conf, '>', "$replica_pgdata/postgresql.auto.conf";
print $conf "synchronous_standby_names = '*'\n";
print $conf "recovery_target_action = 'shutdown'\n";
print $conf "restore_command = 'cp -vr $archivedir/%f $replica_pgdata/%p'\n";
print $conf "recovery_target_name = 'rp_repl_bug'\n";
close $conf;
$replica->adjust_conf('postgresql.conf', 'port', $replica_port);
$replica->start_with_enabled_shutdown;

$replica->start;

# configure primary connection with replication slot
unlink "$replica_pgdata/recovery.signal";
$replica->set_standby_mode;
open $conf, '>', "$replica_pgdata/postgresql.auto.conf";
print $conf "primary_conninfo = ";
print $conf "'user=postgres port=" . $primary->port;
print $conf " host=" . $primary->host;
print $conf " sslmode=prefer sslcompression=1 gssencmode=prefer";
print $conf " krbsrvname=postgres target_session_attrs=any";
print $conf " application_name=gp_walreceiver'\n";
print $conf "primary_slot_name = 'internal_wal_replication_slot'\n";
close $conf;

$replica->reload;

# After restart replica does not start because of error
$replica->restart;

$replica->teardown_node;
$primary->teardown_node;

done_testing();
