#! /usr/bin/env false

use v6.d;

use URL::Grammar;
use URL::Grammar::Actions;

unit class URL;

has Str $.scheme;
has Str $.username;
has Str $.password;
has Str $.hostname;
has Int $.port;
has @.path;
has %.query;
has Str $.fragment;

multi method new (
	Str:D $url,
) {
	my %match = URL::Grammar.parse($url, actions => URL::Grammar::Actions).made;

	die "'$url' failed to parse. Please report the URL you tried to p.spek+perl6@tyil.work." unless %match;

	samewith(
		|%match,
		path => %match<path>.list,
	);
}

multi method new (
	Str :$scheme,
	Str :$username,
	Str :$password,
	Str :$hostname,
	Int :$port,
	:@path = [],
	:%query = {},
	Str :$fragment,
) {
	self.bless(
		:$scheme,
		:$username,
		:$password,
		:$hostname,
		:$port,
		:@path,
		:%query,
		:$fragment,
	);
}

#| Append one or more parts to the path of the URL.
method add-path (
	*@parts,

	--> URL
) {
	return self.new(|self.Hash) unless @parts;

	self.new(
		|self.Hash,
		path => [|@!path, |@parts],
	);
}

#| Append one or more query parameters to the URL.
method add-query (
	*%parts,

	--> URL
) {
	return self.new(|self.Hash) unless %parts;

	self.new(
		|self.Hash,
		query => %(|%!query, |%parts),
	);
}

method Hash (
	--> Hash
) {
	{
		:$!scheme,
		:$!username,
		:$!password,
		:$!hostname,
		:$!port,
		:@!path,
		:%!query,
		:$!fragment,
	}
}

multi method Str (
	--> Str
) {
	my $s = $!scheme ~ "://";

	$s ~= "{self.Str(:userinfo)}@" if $!username;
	$s ~= $!hostname;
	$s ~= ":$!port" if $!port;
	$s ~= "/{self.Str(:path)}" if @!path;
	$s ~= "?{self.Str(:query)}" if %!query;
	$s ~= "#$!fragment" if $!fragment;

	$s;
}

multi method Str (
	:$path! where { $_ },

	--> Str
) {
	@!path.join("/");
}

multi method Str (
	:$query! where { $_ },

	--> Str
) {
	%!query.keys.sort.map({ "$_={%!query{$_}}" }).join("&")
}

multi method Str (
	:$userinfo! where { $_ },

	--> Str
) {
	return "$!username:$!password" if $!password;

	$!username // "";
}

=begin pod

=NAME    URL
=AUTHOR  Patrick Spek <p.spek@tyil.work>
=VERSION 0.2.1

=head1 Synopsis

=head1 Description

=head1 Examples

=head1 See also

=end pod

# vim: ft=perl6 noet
