use Mojo::Base -strict;

use Test::More;
use Mojo::Headers;

# Basic functionality
my $headers = Mojo::Headers->new;
$headers->add(Connection => 'close');
$headers->add(Connection => 'keep-alive');
is $headers->header('Connection'), 'close, keep-alive', 'right value';
$headers->remove('Connection');
is $headers->header('Connection'), undef, 'no value';
$headers->content_type('text/html');
$headers->content_type('text/html');
$headers->expect('continue-100');
$headers->connection('close');
is $headers->content_type, 'text/html', 'right value';
like $headers->to_string, qr/.*\x0d\x0a.*\x0d\x0a.*/, 'right format';
my $hash = $headers->to_hash;
is $hash->{Connection}, 'close',        'right value';
is $hash->{Expect},     'continue-100', 'right value';
is $hash->{'Content-Type'}, 'text/html', 'right value';
$hash = $headers->to_hash(1);
is_deeply $hash->{Connection},     [['close']],        'right structure';
is_deeply $hash->{Expect},         [['continue-100']], 'right structure';
is_deeply $hash->{'Content-Type'}, [['text/html']],    'right structure';
is_deeply [sort @{$headers->names}], [qw(Connection Content-Type Expect)],
  'right structure';
$headers->expires('Thu, 01 Dec 1994 16:00:00 GMT');
$headers->cache_control('public');
is $headers->expires, 'Thu, 01 Dec 1994 16:00:00 GMT', 'right value';
is $headers->cache_control, 'public', 'right value';
$headers->etag('abc321');
is $headers->etag, 'abc321', 'right value';
is $headers->header('ETag'), $headers->etag, 'values are equal';
$headers->status('200 OK');
is $headers->status, '200 OK', 'right value';
is $headers->header('Status'), $headers->status, 'values are equal';

# Mixed case
is $headers->header('content-type' => 'text/plain')->content_type,
  'text/plain', 'right value';
is $headers->header('Content-Type' => 'text/html')->content_type, 'text/html',
  'right value';

# Common headers
$headers = Mojo::Headers->new;
is $headers->accept('foo')->accept,                   'foo', 'right value';
is $headers->accept_charset('foo')->accept_charset,   'foo', 'right value';
is $headers->accept_encoding('foo')->accept_encoding, 'foo', 'right value';
is $headers->accept_language('foo')->accept_language, 'foo', 'right value';
is $headers->accept_ranges('foo')->accept_ranges,     'foo', 'right value';
is $headers->allow('foo')->allow,                     'foo', 'right value';
is $headers->authorization('foo')->authorization,     'foo', 'right value';
is $headers->connection('foo')->connection,           'foo', 'right value';
is $headers->cache_control('foo')->cache_control,     'foo', 'right value';
is $headers->content_disposition('foo')->content_disposition, 'foo',
  'right value';
is $headers->content_encoding('foo')->content_encoding,   'foo', 'right value';
is $headers->content_length('foo')->content_length,       'foo', 'right value';
is $headers->content_range('foo')->content_range,         'foo', 'right value';
is $headers->content_type('foo')->content_type,           'foo', 'right value';
is $headers->cookie('foo')->cookie,                       'foo', 'right value';
is $headers->dnt('foo')->dnt,                             'foo', 'right value';
is $headers->date('foo')->date,                           'foo', 'right value';
is $headers->etag('foo')->etag,                           'foo', 'right value';
is $headers->expect('foo')->expect,                       'foo', 'right value';
is $headers->expires('foo')->expires,                     'foo', 'right value';
is $headers->host('foo')->host,                           'foo', 'right value';
is $headers->if_modified_since('foo')->if_modified_since, 'foo', 'right value';
is $headers->last_modified('foo')->last_modified,         'foo', 'right value';
is $headers->link('foo')->link,                           'foo', 'right value';
is $headers->location('foo')->location,                   'foo', 'right value';
is $headers->origin('foo')->origin,                       'foo', 'right value';
is $headers->proxy_authenticate('foo')->proxy_authenticate, 'foo',
  'right value';
is $headers->proxy_authorization('foo')->proxy_authorization, 'foo',
  'right value';
is $headers->range('foo')->range, 'foo', 'right value';
is $headers->sec_websocket_accept('foo')->sec_websocket_accept, 'foo',
  'right value';
is $headers->sec_websocket_extensions('foo')->sec_websocket_extensions, 'foo',
  'right value';
is $headers->sec_websocket_key('foo')->sec_websocket_key, 'foo', 'right value';
is $headers->sec_websocket_protocol('foo')->sec_websocket_protocol, 'foo',
  'right value';
is $headers->sec_websocket_version('foo')->sec_websocket_version, 'foo',
  'right value';
is $headers->server('foo')->server,                       'foo', 'right value';
is $headers->set_cookie('foo')->set_cookie,               'foo', 'right value';
is $headers->status('foo')->status,                       'foo', 'right value';
is $headers->te('foo')->te,                               'foo', 'right value';
is $headers->trailer('foo')->trailer,                     'foo', 'right value';
is $headers->transfer_encoding('foo')->transfer_encoding, 'foo', 'right value';
is $headers->upgrade('foo')->upgrade,                     'foo', 'right value';
is $headers->user_agent('foo')->user_agent,               'foo', 'right value';
is $headers->vary('foo')->vary,                           'foo', 'right value';
is $headers->www_authenticate('foo')->www_authenticate,   'foo', 'right value';

# Clone
$headers = Mojo::Headers->new;
$headers->add(Connection => 'close');
$headers->add(Connection => 'keep-alive');
is $headers->header('Connection'), 'close, keep-alive', 'right value';
my $clone = $headers->clone;
$headers->connection('nothing');
is $headers->header('Connection'), 'nothing',           'right value';
is $clone->header('Connection'),   'close, keep-alive', 'right value';
$headers = Mojo::Headers->new;
$headers->expect('100-continue');
is $headers->expect, '100-continue', 'right value';
$clone = $headers->clone;
$clone->expect('nothing');
is $headers->expect, '100-continue', 'right value';
is $clone->expect,   'nothing',      'right value';
$clone = Mojo::Headers->new->add(Foo => [qw(bar baz)])->clone;
is_deeply $clone->to_hash(1)->{Foo}, [[qw(bar baz)]], 'right structure';

# Multiline values
$headers = Mojo::Headers->new;
$headers->header('X-Test', [23, 24], 'single line', [25, 26]);
is $headers->to_string,
    "X-Test: 23\x0d\x0a 24\x0d\x0a"
  . "X-Test: single line\x0d\x0a"
  . "X-Test: 25\x0d\x0a 26", 'right format';
my @array = $headers->header('X-Test');
is_deeply \@array, [[23, 24], ['single line'], [25, 26]], 'right structure';
is_deeply $headers->to_hash(1),
  {'X-Test' => [[23, 24], ['single line'], [25, 26]]}, 'right structure';
is_deeply $headers->to_hash, {'X-Test' => '23, 24, single line, 25, 26'},
  'right structure';
my $str = $headers->header('X-Test');
is $str, "23, 24, single line, 25, 26", 'right format';

# Parse headers
$headers = Mojo::Headers->new;
isa_ok $headers->parse(<<'EOF'), 'Mojo::Headers', 'right return value';
Content-Type: text/plain
Expect: 100-continue
Cache-control: public
Expires: Thu, 01 Dec 1994 16:00:00 GMT

EOF
ok $headers->is_finished,   'parser is finished';
is $headers->content_type,  'text/plain', 'right value';
is $headers->expect,        '100-continue', 'right value';
is $headers->cache_control, 'public', 'right value';
is $headers->expires,       'Thu, 01 Dec 1994 16:00:00 GMT', 'right value';

# Parse multiline headers
$headers = Mojo::Headers->new;
$headers->parse(<<'EOF');
Foo: first
 second
 third
Content-Type: text/plain
Foo: first again
  second again

EOF
ok $headers->is_finished, 'parser is finished';
my $multi = [['first', 'second', 'third'], ['first again', 'second again']];
$hash = {'Content-Type' => [['text/plain']], Foo => $multi};
is_deeply $headers->to_hash(1), $hash, 'right structure';
is_deeply [$headers->header('Foo')], $multi, 'right structure';
is scalar $headers->header('Foo'),
  'first, second, third, first again, second again', 'right value';
$headers = Mojo::Headers->new->parse($headers->to_string . "\x0d\x0a\x0d\x0a");
ok $headers->is_finished, 'parser is finished';
is_deeply $headers->to_hash(1), $hash, 'successful roundtrip';
$hash = {
  'Content-Type' => 'text/plain',
  Foo            => 'first, second, third, first again, second again'
};
is_deeply $headers->to_hash, $hash, 'right structure';

# Set headers from hash
$headers = Mojo::Headers->new;
$headers->from_hash({Connection => 'close', 'Content-Type' => 'text/html'});
is_deeply $headers->to_hash,
  {Connection => 'close', 'Content-Type' => 'text/html'}, 'right structure';

# Remove all headers
$headers->from_hash({});
is_deeply $headers->to_hash, {}, 'right structure';

# Append values
$headers = Mojo::Headers->new;
$headers->vary('Accept');
$headers->append(Vary => 'Accept-Encoding');
is $headers->vary, 'Accept, Accept-Encoding', 'right value';
$headers = Mojo::Headers->new;
$headers->append(Vary => 'Accept');
is $headers->vary, 'Accept', 'right value';
$headers->append(Vary => 'Accept-Encoding');
is $headers->vary, 'Accept, Accept-Encoding', 'right value';
$headers = Mojo::Headers->new;
$headers->add(Vary => 'Accept', 'Accept-Encoding');
is_deeply $headers->to_hash(1), {Vary => [['Accept'], ['Accept-Encoding']]},
  'right structure';
$headers->append(Vary => 'Accept-Language');
is_deeply $headers->to_hash(1),
  {Vary => [['Accept, Accept-Encoding, Accept-Language']]}, 'right structure';

# Multiline
$headers = Mojo::Headers->new;
$headers->from_hash(
  {'X-Test' => [[23, 24], ['single line'], [25, 26]], 'X-Test2' => 'foo'});
$hash = $headers->to_hash;
is $hash->{'X-Test'}, '23, 24, single line, 25, 26', 'right value';
is $hash->{'X-Test2'}, 'foo', 'right value';
$hash = $headers->to_hash(1);
is_deeply $hash->{'X-Test'}, [[23, 24], ['single line'], [25, 26]],
  'right structure';
is_deeply $hash->{'X-Test2'}, [['foo']], 'right structure';

# Headers in chunks
$headers = Mojo::Headers->new;
isa_ok $headers->parse(<<EOF), 'Mojo::Headers', 'right return value';
Content-Type: text/plain
EOF
ok !$headers->is_finished, 'parser is not finished';
ok !defined($headers->content_type), 'no value';
isa_ok $headers->parse(<<EOF), 'Mojo::Headers', 'right return value';
X-Bender: Bite my shiny
EOF
ok !$headers->is_finished, 'parser is not finished';
ok !defined($headers->connection), 'no value';
isa_ok $headers->parse(<<EOF), 'Mojo::Headers', 'right return value';
X-Bender: metal ass!

EOF
ok $headers->is_finished, 'parser is finished';
is $headers->content_type, 'text/plain', 'right value';
is $headers->header('X-Bender'), 'Bite my shiny, metal ass!', 'right value';

done_testing();
