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

plan 27;

my $ast;
my $rv;
my RakuDoc::Processor $rdp .= new(:test);

$ast = Q:to/QAST/.AST;
    =begin rakudoc
    Some thing X<to be said> inside spaces.
    =end rakudoc
    QAST
$rv = $rdp.render( $ast, :pre-finalised );
like $rv.body, /
    'Some thing '
    '<markup-X>' .+ 'contents:' .+ 'to be said｣' .+
    'target:' .+ 'index-entry-to_be_said' .+
    '</markup-X>' .+
    ' inside spaces.'
    /, 'X-markup works no meta';
is $rv.index.elems, 1, 'one index entry';
ok $rv.index.keys (cont) 'to be said', 'entry ok';
is $rv.index{'to be said'}<refs>[0]<place>, 'Preface', 'default starting heading';

$ast = Q:to/QAST/.AST;
    =begin rakudoc
    Some thing X<to be said|with index content> inside spaces.
    =end rakudoc
    QAST
$rv = $rdp.render( $ast, :pre-finalised );
like $rv.body, /
    'Some thing '
    '<markup-X>' .+ 'contents:' .+ 'to be said｣' .+
    'target:' .+ 'index-entry-to_be_said' .+
    '</markup-X>' .+
    ' inside spaces.'
    /, 'X-markup works with text and indexed text';
is $rv.index.elems, 1, 'one index entry';
ok $rv.index.keys (cont) 'with index content', 'indexed entry ok';
is $rv.index{'with index content'}<refs>[0]<place>, 'Preface', 'default starting heading';

$ast = Q:to/QAST/.AST;
    =begin rakudoc
    =head First

    Some thing X<to be said|indexed; glossed> inside spaces.

    =head Second

    Another X<stupidity|glossed> over here.

    =end rakudoc
    QAST
$rv = $rdp.render( $ast, :pre-finalised );
like $rv.body, /
    'Some thing '
    '<markup-X' .+ 'contents:' .+ 'to be said｣' .+
    'target:' .+ 'index-entry-to_be_said' .+
    '</markup-X>' .*?
    ' inside spaces.' .+
    'Another '
    '<markup-X>' .+ 'contents:' .+ 'stupidity｣' .+
    'target:' .+ 'index-entry-stupidity' .+
    '</markup-X>'
    /, 'X-markup works with text and indexed text';
is $rv.index.elems, 2, 'two index entry';
ok $rv.index.keys (>=) <glossed indexed>.Set, 'entries ok';
is $rv.index<glossed><refs>[0]<place>, 'First', 'in first heading';
is $rv.index<glossed><refs>[1]<place>, 'Second', 'in second heading';
is $rv.index<indexed><refs>[0]<place>, 'First', 'in 1st heading';
$ast = Q:to/QAST/.AST;
    =begin rakudoc
    =head First

    Some thing X<to be said|indexed; glossed, over> inside spaces.

    =end rakudoc
    QAST
$rv = $rdp.render( $ast, :pre-finalised );
like $rv.body, /
    'Some thing '
    '<markup-X' .+ 'contents:' .+ 'to be said｣' .+
    'target:' .+ 'index-entry-to_be_said' .+
    '</markup-X>' .*?
    ' inside spaces.'
    /, 'X-markup with hierarchical entry';
is $rv.index.elems, 2, 'two index entry';
ok $rv.index.keys (>=) <glossed indexed>.Set, 'entries ok';
ok $rv.index<glossed><sub-index><over>:exists, 'over is in sub-index';
is $rv.index<glossed><sub-index><over><refs>[0]<place>, 'First', 'in first heading';
is $rv.index<indexed><refs>[0]<place>, 'First', 'in 1st heading';
$ast = Q:to/QAST/.AST;
    =begin rakudoc
    =head3 Adding index entries to your text

    An X<index entry|index, entry> is an inline X<formatting code|formatting code;inline formatting> that
    is rendered normally (i.e. with no special identifying styling) within the text, but which is also added
    to the X<index>. X<Index entries|index, entry> may be specified with X<subentries|index, subentry>, including
    X<multilevel subentries|index, subentry, multilevel>, though a renderer is not required to represent anything
    more than the X<first level|index, subentry, rendering>. A single index entry can specify
    X<two or more separate entries in the index|index; index, multiple entries; index, entry, nested>,
    all of which will refer back to the same point in the text.

    =end rakudoc
    QAST
$rv = $rdp.render( $ast, :pre-finalised );
ok $rv.index.keys (>=) ('formatting code', 'index', 'inline formatting').Set, 'index entry list as expected';
ok $rv.index<index><sub-index>.keys (>=) ('entry', 'multiple entries', 'subentry').Set, 'sub entry list ok';
$ast = Q:to/QAST/.AST;
    =begin rakudoc

    X<Statements|Tutorial,statement (Basics)>
    for human readers.

    X<Lexical scope|Tutorial,my (Basics)>

    =end rakudoc
    QAST
lives-ok { $rv = $rdp.render( $ast, :pre-finalised ) }, 'runs double X markup separated by blank line';

$ast = Q:to/QAST/.AST;
    =begin rakudoc
    =head2 X«Lookaround assertions| Regexes,positive lookaround assertion <?>;Regexes,negative lookaround assertion <!>;Regexes,?[ »
    =head2 X<Direct lookup|Syntax,::($c).m;Syntax,A."$m"()>
	=head3 X<$LIST_SEPARATOR, $"|Other languages,$" (Perl)>
    =head1 X<Arrays|Tutorial,array (Basics)>, X<methods|Tutorial,method (Basics)> and X<invocants|Tutorial,invocant (Basics)>
    =end rakudoc
    QAST
my %expected =
    Regexes => %(
        refs => [],
        sub-index => %(
            'positive lookaround assertion <?>' => %(
                refs => [
                    %(:is-inheading, :place<Lookaround assertions>, :target<index-entry-Lookaround-assertions> ),
                ],
                :sub-index( %() )
            ),
            'negative lookaround assertion <!>' => %(
                refs => [
                    %(:is-inheading, :place<Lookaround assertions>, :target<index-entry-Lookaround-assertions> ),
                ],
                :sub-index( %() )
            ),
            '?[' => %(
                refs => [
                    %(:is-inheading, :place<Lookaround assertions>, :target<index-entry-Lookaround-assertions> ),
                ],
                :sub-index( %() )
            ),
        ),
    ),
    Syntax => %(
        refs => [],
        sub-index => %(
            '::($c).m' => %(
                refs => [
                    %(:is-inheading, :place<Direct lookup>, :target<index-entry-Direct_lookup> ),
                ],
                :sub-index( %() )
            ),
            'A."$m"()' => %(
                refs => [
                    %(:is-inheading, :place<Direct lookup>, :target<index-entry-Direct_lookup> ),
                ],
                :sub-index( %() )
            ),
        ),
    ),
    'Other languages' => %(
        refs => [],
        sub-index => %(
            '$" (Perl)' => %(
                refs => [
                    %(:is-inheading, :place<$LIST_SEPARATOR, $">, :target<index-entry-$LIST_SEPARATOR,_$"> ),
                ],
                :sub-index( %() )
            ),
        ),
    ),
    Tutorial => %(
        refs => [],
        sub-index => %(
            'array (Basics)' => %(
                refs => [
                    %(:is-inheading, :place<Arrays>, :target<index-entry-Arrays> ),
                ],
                :sub-index( %() )
            ),
            'method (Basics)' => %(
                refs => [
                    %(:is-inheading, :place<methods>, :target<index-entry-methods> ),
                ],
                :sub-index( %() )
            ),
            'invocant (Basics)' => %(
                refs => [
                    %(:is-inheading, :place<invocants>, :target<index-entry-invocants> ),
                ],
                :sub-index( %() )
            ),
        ),
    ),
;
$rv = $rdp.render( $ast, :pre-finalised );
is +$rv.warnings, 0, 'No warnings issued';

is-deeply $rv.index.keys.sort, %expected.keys.sort, 'sorted index keys as expected';
is-deeply $rv.index.sort.map({ .key, .value<sub-index>.keys.sort.Slip }).Slip,
%expected.sort.map({ .key, .value<sub-index>.keys.sort.Slip }).Slip,
    'sorted index and subindex keys as expected';
is-deeply $rv.index.sort.map({ (.key, .value<refs>.elems).Slip }), %expected.sort.map({ (.key, .value<refs>.elems).Slip }), 'direct ref elems are all zero';

done-testing;
