#!/usr/bin/env perl
# -*- mode: perl; coding: utf-8 -*-
#----------------------------------------
use strict;
use warnings qw(FATAL all NONFATAL misc);
use FindBin;
BEGIN {
  if (-d (my $dir = "$FindBin::RealBin/../../../../t")) {
    local (@_, $@) = $dir;
    do "$dir/t_lib.pl";
    die $@ if $@;
  }
}

use Cwd ();
my ($app_root);
BEGIN {
  if (-r __FILE__) {
    # detect where app.psgi is placed.
    $app_root = dirname(dirname(File::Spec->rel2abs(__FILE__)));
  } else {
    # older uwsgi do not set __FILE__ correctly, so use cwd instead.
    $app_root = Cwd::cwd();
  }
}
#----------------------------------------
use 5.010; no if $] >= 5.017011, warnings => "experimental";

use Carp;
use YATT::Lite::Breakpoint;
use YATT::Lite::Util qw(ostream lexpand);
use YATT::Lite::Test::XHFTest2; # To import Item class.
use base qw(YATT::Lite::Test::XHFTest2); # XXX: Redundant, but required.

BEGIN {
  foreach my $req (qw(Plack)) {
    unless (eval qq{require $req}) {
      plan skip_all => "$req is not installed."; exit;
    }
  }
}


use YATT::t::t_preload; # To make Devel::Cover happy.

my MY $tests = MY->load_tests([dir => "$FindBin::Bin/../html"]
			      , @ARGV ? @ARGV : $FindBin::Bin);
$tests->enter;

plan $tests->test_plan;

my $dispatcher = $tests->load_dispatcher;
$dispatcher->configure(is_psgi => 0);

foreach my File $sect (@{$tests->{files}}) {
  my $dir = $tests->{cf_dir};
  my $sect_name = $tests->file_title($sect);
  foreach my Item $item (@{$sect->{items}}) {
  SKIP: {
      if ($item->{cf_PERL_MINVER} and $] < $item->{cf_PERL_MINVER}) {
	Test::More::skip "by perl-$] < PERL_MINVER($item->{cf_PERL_MINVER}) $sect_name", 1;
      }

      if (my $action = $item->{cf_ACTION}) {
	my ($method, @args) = @$action;
	my $sub = $tests->can("action_$method")
	  or die "No such action: $method";
	$sub->($tests, @args);
	next;
      }

      my %env = (DOCUMENT_ROOT => $dir
		 , PATH_INFO => "/$item->{cf_FILE}"
		 , PATH_TRANSLATED => "$dir/$item->{cf_FILE}"
		);

      $item->{cf_METHOD} //= 'GET';
      my $T = defined $item->{cf_TITLE} ? "[$item->{cf_TITLE}]" : '';

      my $con = ostream(my $buffer);
      eval {
	if ($item->{cf_BREAK}) {
	  YATT::Lite::Breakpoint::breakpoint();
	}
	my $params = $item->{cf_PARAM};
	if (defined $params) {
	  if (ref $params eq 'ARRAY'
	      and grep(ref $_ eq 'HASH', @$params)
	      or ref $params eq 'HASH'
	      and grep(ref $_ eq 'HASH', values %$params)) {
	    croak "HASH value is not allowed in PARAM block!";
	  }
	}
	$dispatcher->cf_let([noheader => 0
			     , lexpand($item->{cf_SITE_CONFIG})]
			    , runas => cgi => $con, \%env
			    , [$params])
      };

      my $header;
      if ($item->{cf_ERROR}) {
	like $@, qr{$item->{cf_ERROR}}
	  , "[$sect_name] $T ERROR $item->{cf_METHOD} $item->{cf_FILE}";
	next;
      } elsif (ref $@ eq 'SCALAR' and ${$@} eq 'DONE') {
	# Request is completed.
      } elsif (ref $@ eq 'ARRAY' and @{$@} == 3) {
	# PSGI triple was raised.
	$header = join("\n", @{$@->[1]});
      } elsif ($@) {
	Test::More::fail $item->{cf_FILE};
	Test::More::diag $@;
	next;
      }


      if ($buffer =~ s/\A((?:[^\n\r]+\r?\n)*\r?\n)//) {
	$header = $1;
      }

      if ($item->{cf_METHOD} eq 'POST' and $item->{cf_HEADER}) {
	$header //= trimlast(nocr($buffer));
	like $header, $tests->mkpat($item->{cf_HEADER})
	  , "[$sect_name] $T POST $item->{cf_FILE}";
      } elsif (ref $item->{cf_BODY}) {
	like nocr($buffer), $tests->mkseqpat($item->{cf_BODY})
	  , "[$sect_name] $T $item->{cf_METHOD} $item->{cf_FILE}";
      } else {
	eq_or_diff trimlast(nocr($buffer)), $item->{cf_BODY}
	  , "[$sect_name] $T $item->{cf_METHOD} $item->{cf_FILE}";
      }
    }
  }
}

sub test_plan {
  my MY $self = shift;
  # XXX: This is overkill!
  foreach my File $file (@{$self->{files}}) {
    if ($file->{cf_USE_COOKIE}) {
      return skip_all => "Cookie is not yet supported in offline.t";
    }
  }
  $self->SUPER::test_plan;
}
