#!/usr/bin/perl

use English qw(-no_match_vars);
use common::sense;
use FindBin;
use lib "$FindBin::Bin/../lib";
# DBIx::Class is used implicitly via a 'Schema':
use Book::Schema;
use Test2::V0;
use Test2::Plugin::BailOnFail;

# Connect.
my $schema = Book::Schema->connect('dbi:Pg:dbname=pg_book_catalog', 'pgc_owner');
isa_ok(
   $schema, ["Book::Schema"],
   "Acquired our Book::Schema object."
);

# Retrieve our author.
my $rset_author = $schema->resultset('Author');
isa_ok(
   $rset_author, ["DBIx::Class::ResultSet"],
   "Acquired DBIx::Class::ResultSet for Author."
);

my $austen = $rset_author->find({ name => "Jane Austen" });
isa_ok(
   $austen, [ "Book::Schema::Result::Author" ],
   "Retrieved author object is a Book::Schema::Result::Author." );

# Open a scope to contain the variable for _sc and _lc variants of
# what's returned by ->books.  Prevents their inadvertent use later.
diag("Testing the effect of context on the books() and books_rs() accessors.");
{
   my $austen_books_sc = $austen->books;
   isa_ok(
      $austen_books_sc, ["DBIx::Class::ResultSet"],
      "The books() accessor (scalar context) returns a DBIx::Class::ResultSet."
   );
   my @austen_books_lc = ($austen->books);
   is(
      scalar @austen_books_lc, 0,
      "The books() accessor (list context) returns an empty list."
   );
   my $austen_books_scrs = $austen->books_rs;
   isa_ok(
      $austen_books_scrs, ["DBIx::Class::ResultSet"],
      "The books_rs() accessor (scalar context) returns a ResultSet."
   );
}

my ($austen_books) = ($austen->books_rs);
isa_ok(
   $austen_books, ["DBIx::Class::ResultSet"],
   "The books_rs() accessor (list context) returns a ResultSet."
);
diag("Done with context tests.");

is($austen_books->count, 0, "count() returns zero, no books yet.");
# Use negative gutenberg_ids to avoid collisions.
my $gid = -1;
my $persuasion = $austen_books->create({
   gutenberg_id => $gid--, title => "Persuasion",
});
isa_ok(
   $persuasion, ["Book::Schema::Result::Book"],
   "Created a Book::Schema::Result::Book for Austen."
);

$austen_books->create({
   gutenberg_id => $gid--, title => "Emma",
});
is($austen_books->count, 2, "Austen wrote two books now.");

my @books = ($austen->books);
is(scalar @books, 2,
   "The books() accessor in list context now returns a list of 2."
);
isa_ok($books[0], ["Book::Schema::Result::Book"],
   "The list contains Book::Schema::Result::Book objects.",
);

# Time for Dickens to write something.
my $dickens = $rset_author->find({ name => "Charles Dickens" });
my $dickens_books = $dickens->books_rs;  # preferring _rs for its consistency.
$dickens_books->create({
   gutenberg_id => $gid--, title => "Oliver Twist"
});
$dickens_books->create({
   gutenberg_id => $gid--, title => "A Christmas Carol",
});
$dickens_books->create({
   gutenberg_id => $gid--, title => "Great Expectations",
});
is($dickens_books->count, 3, "Dickens has 3 books.");

# Retrieve a book and its author together using prefetch.
my $rset_book = $schema->resultset('Book');
isa_ok(
   $rset_book, ["DBIx::Class::ResultSet"],
   "Acquired a DBIx::Class::ResultSet for books."
);
# Now we need a second resultset, returned by a search on the first.
my $rset_oliver_twist = $rset_book->search_rs(
   { gutenberg_id => { '<' => 0 }, "me.title" => "Oliver Twist" },
   { prefetch => [ "author" ] },
);
isa_ok(
   $rset_oliver_twist, ["DBIx::Class::ResultSet"],
   "Retrieved a DBIx::Class::ResultSet for Oliver Twist."
);
# Get the book object out of the resultset.
my $oliver_twist = $rset_oliver_twist->next;
isa_ok(
   $oliver_twist, ["Book::Schema::Result::Book"],
   "The result set has the Book::Schema::Result::Book for Oliver Twist."
);
is($oliver_twist->title, "Oliver Twist", "Retrieved Oliver Twist.");
is($oliver_twist->author->name, "Charles Dickens", "By Charles Dickens.");
is(
   $rset_oliver_twist->next, undef,
   "Nothing more in the result set for Oliver Twist."
);

# Try getting books whose title contains the letter "e". Also use the
# _rs variant of search.
my $rset_e = $rset_book->search_rs(
   {  "me.title" => { ilike => '%e%' },  # case-insensitive
      gutenberg_id => { '<' => 0 },
   },
   {  prefetch => [ "author" ],
      order_by => [ "me.title" ],
   },
);
is($rset_e->count, 4, "Four book titles have letter E or e.");

# Expecting Emma, Great Expectations, Oliver Twist and Persuasion, in order.
my $em = $rset_e->next;
is($em->title, "Emma", "Found Emma.");
is($em->author->name, "Jane Austen", "By Jane Austen.");
my $ge = $rset_e->next;
is($ge->title, "Great Expectations", "Found Great Expectations.");
is($ge->author->name, "Charles Dickens", "By Charles Dickens.");
my $ot = $rset_e->next;
is($ot->title, "Oliver Twist", "Found Oliver Twist.");
is($ot->author->name, "Charles Dickens", "By Charles Dickens.");
my $p = $rset_e->next;
is($p->title, "Persuasion", "Found Persuasion.");
is($p->author->name, "Jane Austen", "By Jane Austen.");
ok(! $rset_e->next, "No more books found.");

done_testing;
exit(0);
