use lib 'lib';
use lib 'specs/support';
use BDD::Behave;
use BloginTest;
use Blogin::Site;

my $PAGINATED = 'specs/fixtures/paginated'.IO;
my $BASIC     = 'specs/fixtures/basic'.IO;


sub build-paginated(IO::Path:D $out, *%options) {
  Blogin::Site::build(
    content => $PAGINATED.add('content'),
    out     => $out,
    layouts => $PAGINATED.add('layouts'),
    page-size => 2,
    |%options,
  );
}

describe 'per-section paginated listings', {
  let(:out, { temp-dir('page') });

  after-each { nuke(out()) }

  it 'writes the first listing page at the section path', {
    build-paginated(out());
    expect(out().add('posts.html').e).to.be-truthy;
  }

  it 'writes the second listing page under page/2', {
    build-paginated(out());
    expect(out().add('posts/page/2.html').e).to.be-truthy;
  }

  it 'lists the newest posts first on page one', {
    build-paginated(out());
    my $html = out().add('posts.html').slurp;
    expect($html.contains("href='/posts/alpha'") && $html.contains("href='/posts/bravo'")).to.be-truthy;
  }

  it 'keeps the overflow post off page one', {
    build-paginated(out());
    expect(out().add('posts.html').slurp.contains("href='/posts/charlie'")).to.be-falsy;
  }

  it 'includes each post description in the listing', {
    build-paginated(out());
    expect(out().add('posts.html').slurp.contains('The alpha summary.')).to.be-truthy;
  }

  it 'falls back to the opening content block when a post has no description', {
    build-paginated(out());
    expect(out().add('posts.html').slurp.contains('Bravo body.')).to.be-truthy;
  }

  it 'shows a post lead image in the listing', {
    build-paginated(out());
    expect(out().add('posts.html').slurp.contains("src='/assets/img/alpha-chart.png'")).to.be-truthy;
  }

  it 'omits the image element for a post with no lead image', {
    build-paginated(out());
    expect(out().add('essays.html').slurp.contains('post-image')).to.be-falsy;
  }

  it 'puts the overflow post on page two', {
    build-paginated(out());
    expect(out().add('posts/page/2.html').slurp.contains("href='/posts/charlie'")).to.be-truthy;
  }

  it 'links forward from page one to page two', {
    build-paginated(out());
    expect(out().add('posts.html').slurp.contains('href="/posts/page/2"')).to.be-truthy;
  }

  it 'links back from page two to page one', {
    build-paginated(out());
    expect(out().add('posts/page/2.html').slurp.contains('href="/posts"')).to.be-truthy;
  }

  it 'numbers the pages in the built-in pagination', {
    build-paginated(out());
    my $html = out().add('posts.html').slurp;
    expect($html.contains('>1</span>') && $html.contains('>2</a>')).to.be-truthy;
  }

  it 'marks the current page with an aria-current span', {
    build-paginated(out());
    expect(out().add('posts.html').slurp.contains('aria-current="page"')).to.be-truthy;
  }

  it 'shows an older-posts link on the first page but no newer-posts link', {
    build-paginated(out());
    my $html = out().add('posts.html').slurp;
    expect($html.contains('rel="next"') && !$html.contains('rel="prev"')).to.be-truthy;
  }

  it 'shows a newer-posts link on the last page', {
    build-paginated(out());
    expect(out().add('posts/page/2.html').slurp.contains('rel="prev"')).to.be-truthy;
  }
}

describe 'a long pagination bar stays a fixed width', {
  let(:src, { temp-dir('winsrc') });
  let(:out, { temp-dir('winout') });

  before-each {
    src().add('posts').mkdir;
    for 1 .. 12 -> $number {
      my $day = sprintf('%02d', $number);
      src().add("posts/2026-07-{$day}-post-{$number}.md").spurt(
        "---\ntitle: Post $number\ndate: 2026-07-$day\n---\nbody $number\n"
      );
    }
  }

  after-each { nuke(src()); nuke(out()); }

  sub build-window(*%options) {
    Blogin::Site::build(
      content => src(),
      out     => out(),
      layouts => $BASIC.add('layouts'),
      page-size => 1,
      |%options,
    );
  }

  it 'numbers only the three pages on either side of the current one', {
    build-window();
    my $html = out().add('posts/page/6.html').slurp;
    expect($html.contains('>3</a>') && $html.contains('>9</a>')).to.be-truthy;
  }

  it 'leaves out pages beyond the window', {
    build-window();
    my $html = out().add('posts/page/6.html').slurp;
    expect($html.contains('>2</a>') || $html.contains('>10</a>')).to.be-falsy;
  }

  it 'reaches the first page through a first control', {
    build-window();
    expect(out().add('posts/page/6.html').slurp.contains('aria-label="First"')).to.be-truthy;
  }

  it 'reaches the last page through a last control', {
    build-window();
    expect(out().add('posts/page/6.html').slurp.contains('aria-label="Last"')).to.be-truthy;
  }

  it 'writes a single page for a short section', {
    build-paginated(out());
    expect(out().add('essays.html').e && !out().add('essays/page/2.html').e).to.be-truthy;
  }
}

describe 'numbered pagination links a layout can render itself', {
  let(:out, { temp-dir('numbered') });

  after-each { nuke(out()) }

  it 'links each page by number from the first page', {
    build-paginated(out());
    my $html = out().add('posts.html').slurp;
    expect($html.contains('<ol class=\'page-numbers\'>') && $html.contains('href=\'/posts/page/2\'')).to.be-truthy;
  }

  it 'marks the current page instead of linking it', {
    build-paginated(out());
    expect(out().add('posts/page/2.html').slurp.contains('<li class=\'current\'>2</li>')).to.be-truthy;
  }

  it 'omits the numbered list for a single-page section', {
    build-paginated(out());
    expect(out().add('essays.html').slurp.contains('page-numbers')).to.be-falsy;
  }

  it 'numbers the home section pages from the root', {
    build-paginated(out(), home-section => 'posts');
    expect(out().add('index.html').slurp.contains('href=\'/page/2\'')).to.be-truthy;
  }
}

describe 'adjacent post navigation within a section', {
  let(:out, { temp-dir('post-nav') });

  before-each { build-paginated(out()) }
  after-each  { nuke(out()) }

  it 'links a middle post to the newer neighbor', {
    expect(out().add('posts/bravo.html').slurp.contains("href=\"/posts/alpha\"")).to.be-truthy;
  }

  it 'links a middle post to the older neighbor', {
    expect(out().add('posts/bravo.html').slurp.contains("href=\"/posts/charlie\"")).to.be-truthy;
  }

  it 'omits the newer link on the newest post', {
    expect(out().add('posts/alpha.html').slurp.contains('class="prev"')).to.be-falsy;
  }

  it 'omits the older link on the oldest post', {
    expect(out().add('posts/charlie.html').slurp.contains('class="next"')).to.be-falsy;
  }

  it 'shows no navigation for a section with a single post', {
    expect(out().add('essays/first-essay.html').slurp.contains('post-nav')).to.be-falsy;
  }
}

describe 'the home section at the site root', {
  let(:out, { temp-dir('home') });

  after-each { nuke(out()) }

  it 'writes the home section listing to the root index', {
    build-paginated(out(), home-section => 'posts');
    expect(out().add('index.html').e).to.be-truthy;
  }

  it 'paginates the home section at the root', {
    build-paginated(out(), home-section => 'posts');
    expect(out().add('page/2.html').e).to.be-truthy;
  }

  it 'lists the newest posts on the root index', {
    build-paginated(out(), home-section => 'posts');
    expect(out().add('index.html').slurp.contains("href='/posts/alpha'")).to.be-truthy;
  }

  it 'renders the root through the home template when one exists', {
    build-paginated(out(), home-section => 'posts');
    expect(out().add('index.html').slurp.contains('Welcome')).to.be-truthy;
  }

  it 'leaves the section listing on the plain index template', {
    build-paginated(out(), home-section => 'posts');
    expect(out().add('posts.html').slurp.contains('Welcome')).to.be-falsy;
  }

  it 'links the root index forward to its second page', {
    build-paginated(out(), home-section => 'posts');
    expect(out().add('index.html').slurp.contains('href="/page/2"')).to.be-truthy;
  }

  it 'titles the root index with the site title alone', {
    build-paginated(out(), home-section => 'posts', site => %( title => 'My Blog' ));
    expect(out().add('index.html').slurp.contains('<title>My Blog</title>')).to.be-truthy;
  }

  it 'prefixes the site title before the section label on a listing', {
    build-paginated(out(), home-section => 'posts', site => %( title => 'My Blog' ));
    expect(out().add('posts.html').slurp.contains('<title>My Blog :: Posts</title>')).to.be-truthy;
  }
}
