use v6.d;
use Test;
use RakuDoc::PromiseStrings;

plan 54;

my $register = PCellTracker.new;
my $payload;

#tests of PCell
my PCell $pc .= new(:$register, :id<FFF>);
#duplicate with same id
my PCell $pc2 .= new(:$register, :id<FFF>);
nok $pc.is-expanded, 'PCell not expanded yet';
is $pc.Str, '｢FFF UNAVAILABLE｣', 'stringifies with an unavailable message';
is $pc2.Str, '｢FFF UNAVAILABLE｣', 'duplicate stringifies with an unavailable message';
is-deeply $register.list-unexpanded, %( FFF => '', ), 'lists one unexpanded PCell';
like $pc.debug, / 'Waiting for: FFF' /,'debug string with id';
$payload = 'some stuff';
$register.add-payload(:$payload, :id<FFF>);
like $pc.debug, / 'Expanded to:' /,'Expanding changes debug str';
is $pc.Str, 'some stuff', 'stringifies with payload';
is $pc2.Str, 'some stuff', 'duplicate stringifies with payload';
ok $pc.is-expanded, 'PCell now expanded';
is-deeply $register.list-unexpanded, %(), 'lists no unexpanded PCell';
# create PCell with id thats been emitted
$pc2 .= new(:$register, :id<FFF>);
is $pc2.Str, 'some stuff', 'stringifies with payload after id emitted';
# tests of PStr
my PStr $s .= new;
lives-ok { $s ~= PCell.new(:$register, :id<AAA>) }, 'right concatenation of PCell lives';
is $s.Str, '｢AAA UNAVAILABLE｣', 'PCell stringifies with UNAVAILABLE';
ok $s.has-PCells, 'finds PCells in string';
lives-ok { $s ~= "Some stuff " }, 'right concatenation of Str lives';
$s ~= PCell.new(:$register, :id<BBB>);
is $s.Str, '｢AAA UNAVAILABLE｣Some stuff ｢BBB UNAVAILABLE｣', 'still UNAVAILABLE';
like ([~] $s.has-PCells), / 'Waiting for' .+ 'AAA' .+ 'BBB' /, 'got debug messsages of two PCells in string';
$payload = 'second value first';
$register.add-payload(:$payload, :id<BBB>);
like $s.Str, / 'AAA' .+ $payload /, 'AAA is still unavailable, payload now in stringification';
lives-ok { sink '<start tab>' ~ $s }, 'left concatenation works';
like $s.Str, / 'start tab' .+ 'AAA' .+ $payload /, 'string added to start';
like $s.debug, /
    'PCell'
    .+ 'Waiting for: AAA'
    /, 'debug method works';
ok $s.has-PCells, 'There are PCells in the PStr';
$payload = 'first value now';
$register.add-payload(:$payload, :id<AAA>);
unlike $s.debug, / 'PCell, Waiting' /, 'debug shows no waiting';
unlike $s.Str, / AAA /, 'AAA UNKNOWN removed';
like $s.Str, / $payload /, 'replaced  by payload';
sink '<begin>' ~ $s ~ '<end>';
like $s.Str, /  '<begin>' .+ '<end>' $ /, 'multiple concatenations';
nok $s.has-PCells, 'strip removes all expanded PCells';
my $rv = $s.Str;
is $rv, '<begin><start tab>first value nowSome stuff second value first<end>', '$s now just a string';
is $s.lead, $rv, 'lead same as whole string';
is $s.tail, $rv, 'tail same as whole string';

$s .= new;
$s ~= 'start' ~ PCell.new(:$register, :id('QQQ'));
like $s.Str, / 'start' .+ 'QQQ'/, 'concatenation with starting Str';
sink 'more at front ' ~ $s;
is $s.lead, 'more at front start', 'concatenated front strings';
$s ~= ' with stuff at end' ~ ' <end>';
is $s.tail, ' with stuff at end <end>', 'concatenated final strings';

# test trim
lives-ok { $s .= new: ' one ', PCell.new(:$register, :id('QQQ')), ' two '},
        'creates a new Pstr from a list';
$rv = $s;
like $s.Str, / ' one ' .+ 'QQQ' .+ ' two ' /, 'expected PStr';
$s.trim-trailing;
like $s.Str, / ' one ' .+ 'QQQ' .+ ' two' $ /, 'should trim trailing space';
$s.trim-leading;
like $s.Str, / ^ 'one ' .+ 'QQQ' .+ ' two' $ /, 'should trim leading space';
is $s.segments, 3, 'trimming should not change segments';
$rv.trim;
isa-ok $rv, PStr, 'rv remains a PStr after a trim';
isa-ok $rv.trim, PStr, 'rv.trim yields a PStr';
like $rv.Str, / ^ 'one ' .+ 'QQQ' .+ ' two' $ /, 'should trim leading/trailing space';
is $rv.segments, 3, 'trim should not change segments';
$s .= new( '  just a single string ');
is $s.segments, 1, 'simple string is one segment';
$s.trim;
like $s.Str, / ^ 'just a single string' $ /, 'trims start/end space without repeating';

$s .= new: ' one ', PCell.new(:$register, :id('QQQ')), ' two ';
my PStr $v .= new: ' three ', PCell.new(:$register, :id('QQQ')), ' four ', $s;
is $v.segments, 6, 'new takes segments from a PStr';

my $str = 'String';
$str ~= PCell.new(:$register, :id('NewID'));
isa-ok $str, PStr, 'string coerced to PStr if PCell added to it';
$str = 'string';
$s .= new: ' one ', PCell.new(:$register, :id('PPPPP')), ' two ';
$str ~= $s;
isa-ok $str, PStr, 'string coerced to PStr if PStr added to it';
my $str2 = 'New str';
$s .= new: ' One ', PCell.new(:$register, :id('GGGGGG')), ' two ';
$str ~= $str2 ~ ': ｢' ~ $s ~  "｣\n";
isa-ok $str, PStr, 'string coerced to PStr if seq of str & PStr concated to it';
$s .= new: 'One Two Three', PCell.new(:$register, :id('IJOEJOIJ')), ' Four Five TwoTwo';

like $s.lc, /^ 'one two three' .+ 'four five' /, 'lower case works';
like $s.uc, /^ 'ONE TWO THREE' .+ 'FOUR FIVE' /, 'upper case works';
like $s.tc, /^ 'ONE TWO THREE' .+ 'FOUR FIVE' /, 'tc case works';
like $s.tclc, /^ 'One two three' .+ 'four five' /, 'tclc case works';
like $s.subst(/ 'two' /,'Twenty',:g), / 'One Twenty three' .+ 'five TwentyTwenty' /, 'subst works';
$register.add-payload(:payload<payload stuff>, :id<IJOEJOIJ>);
like $s, / 'payload stuff' /, 'PStr structure maintained until add-payload';

done-testing;
