#!/usr/bin/env perl
use v5.24;
use utf8;
use warnings;
use experimental 'signatures';
no warnings 'experimental::signatures';

use Test::More;
use Test::Exception;
use Encode qw< decode encode >;
use File::Basename 'basename';

use Data::Resolver::Asset;

subtest 'basic tests' => sub {
   my $asset;
   lives_ok {
      $asset = Data::Resolver::Asset->new(key => foo => raw => 'data')
   }
   'instantiation of a basic asset';

   my $rr = $asset->raw_ref;
   isa_ok $rr, 'SCALAR';
   is $$rr, 'data', 'contents as data from raw ref';
   is $asset->raw_data, 'data', 'contents as data from raw_data';

   ok ! $asset->has_filehandle, 'no filehandle present by default';
   ok ! $asset->has_file, 'no file present by default';
   my $fh = $asset->filehandle;
   ok ! $asset->has_file, 'still no file present by default';

   my @stat = silent_stat($fh);
   ok scalar(@stat) == 0, 'stat failed (in-memory filehandle)';

   isa_ok $fh, 'GLOB';
   my $fhdata = slurp_raw($fh);
   is $fhdata, 'data', 'data from filehandle';
   ok ! $asset->has_filehandle, 'no filehandle present anyway';

   my $file = $asset->file;
   ok -e $file, 'file exists';
   is basename($file), 'foo', 'filename as expected';
   my $filedata = slurp_raw($file);
   is $filedata, 'data', 'data from file';
   ok ! $asset->has_filehandle, 'no filehandle present anyway';
};

subtest 'filehandle not_from_memory' => sub {
   my $asset = Data::Resolver::Asset->new(key => foo => raw => 'data');

   ok ! $asset->has_filehandle, 'no filehandle present by default';
   ok ! $asset->has_file, 'no file present by default';

   my $fh = $asset->filehandle(not_from_memory => 1);
   ok $asset->has_file, 'file created after not_from_memory';

   my @stat = silent_stat($fh);
   ok scalar(@stat) > 0, 'stat was successful';

   isa_ok $fh, 'GLOB';
   my $fhdata = slurp_raw($fh);
   is $fhdata, 'data', 'data from filehandle';
   ok ! $asset->has_filehandle, 'no filehandle present anyway';
};

subtest 'key inference and caching' => sub {
   my $asset = Data::Resolver::Asset->new(key => foo => raw => 'data');
   ok ! $asset->has_filehandle, 'no filehandle present by default';
   ok ! $asset->has_file, 'no file present by default';
   my $file = $asset->file;
   ok -e $file, 'file exists';
   is basename($file), 'foo', 'filename as expected';

   $asset = Data::Resolver::Asset->new(file => $file);
   is $asset->key, 'foo', 'key auto-inferred from filename';
   ok $asset->has_file, 'asset has a file component';
   ok ! $asset->has_filehandle, 'asset has no filehandle';
   ok ! $asset->has_raw_ref, 'asset has no reference to raw data';
   is $asset->raw_data, 'data', 'raw_data';
   ok $asset->has_raw_ref, 'asset has a cached reference to raw data now';

   is slurp_raw($asset->filehandle), 'data', 'all data from filehandle';
};

subtest 'parsed_as_json' => sub {
   my $asset = Data::Resolver::Asset->new(key => foo => raw => '[1,2,3]');
   is_deeply $asset->parsed_as_json, [1..3], 'decoded_as_json';
};

subtest 'decoded_as_utf8' => sub {
   my $e_str  = 'è';
   my $e_utf8 = encode('UTF-8', $e_str);

   my $asset = Data::Resolver::Asset->new(key => foo => raw => $e_utf8);
   my $back = $asset->decoded_as_utf8;
   is $back, $e_str, 'getting stuff as UTF-8';
};

subtest useability => sub {
   my $asset = Data::Resolver::Asset->new(key => foo => raw => 'foobar');
   ok $asset->is_useable, 'asset is useable';
   lives_ok { $asset->assert_useable } 'does not complain too';

   my $buffer = 'whatever';
   open my $fh, '<:raw', \$buffer or die "open(): $!";
   $asset = Data::Resolver::Asset->new(key => foo => filehandle => $fh);
   ok $asset->is_useable, 'asset is useable (with filehandle only)';
   is slurp_raw($asset->filehandle), 'whatever', 'data from filehandle';
   ok ! $asset->is_useable, 'asset no useable any more';
   dies_ok { $asset->assert_useable } 'useability assertion throws';
};

done_testing();

sub slurp_raw ($fh) {
   if (ref($fh) ne 'GLOB') {
      open my $h, '<', $fh or die "open('$fh'): $!";
      $fh = $h;
   }
   binmode $fh, ':raw' or die $!;
   local $/;
   <$fh> or die $!;
}

sub silent_stat ($fh) { no warnings; stat($fh) }
