#!/usr/bin/env perl
use strict;
use warnings;

# utf8 shenanis -- files written and stdout both utf8
use utf8;
use open qw(:std :encoding(UTF-8));

use LWP::UserAgent;
use JSON::PP;
use Data::Dumper;

if (!$ENV{SPOTIFY_TOKEN}) {
	die "SPOTIFY_TOKEN not set in environment\n";
}

if (!@ARGV) {
	die "usage: $0 username\n";
}

my $user = $ARGV[0];
my $API = "https://api.spotify.com/v1";
my $ua = LWP::UserAgent->new();
$ua->default_header("Authorization" => "Bearer $ENV{SPOTIFY_TOKEN}");

sub get_playlists {
	my $limit = shift;
	$limit //= 10000;
	my @playlists;
	my $url = "$API/users/$user/playlists";
	while (1) {
		my $res = $ua->get($url);
		if (!$res->is_success) {
			print(Dumper($res));
			my $err = $res->decoded_content;
			die "Failed to fetch playlists: $err";
		}
		my $j = decode_json($res->decoded_content);
		foreach my $item (@{$j->{items}}) {
			push(@playlists, $item);
		}
		if (!$j->{next} || scalar @playlists > $limit) {
			last;
		}
		print("Paging Playlists: $url\n");
		$url = $j->{next};
	}
	return @playlists;
}

sub describe {
	my $p = shift;
	my $desc = $p->{description} ? "\"$p->{description}\"\n\n" : "";
	my $s = <<EOM;
# $p->{name}

${desc}By $p->{owner}->{display_name}

EOM
	my $url = "$API/playlists/$p->{id}?fields=tracks.next,tracks.items(added_at,track.name,track.artists(name))";
	if ($p->{id} eq "LIBRARY") {
		$url = "$API/me/tracks";
	}
	my $i = 1;
	while (1) {
		my $res = $ua->get($url);
		if (!$res->is_success) {
			print(Dumper($res));
			my $err = $res->decoded_content;
			die "Failed to fetch playlist: $err";
		}
		# NOTE: after paging, the shape changes..
		my $j = decode_json($res->decoded_content);
		my $tracks = $j->{tracks} || $j;
		my $n = scalar @{$tracks->{items}};
		print("$n Tracks\n");
		foreach my $t (@{$tracks->{items}}) {
			(my $d = $t->{added_at}) =~ s/T.*Z$//;
			my $fart = @{$t->{track}->{artists}}[0]->{name};
			$s .= sprintf(
				"[%s] %-4d \"%s\" by %s\n",
				$d, $i, $t->{track}->{name}, $fart,
			);
			$i += 1;
		}
		if (!$tracks->{next}) {
			last;
		}
		# HACK: the fields filter breaks in the next URL,
		# so we have to strip the tracks. prefix
		($url = $tracks->{next}) =~ s/tracks\.//g;
	}
	return $s;
}

sub writep {
	my $p = shift;
	my $desc = describe($p);
	(my $fname = $p->{name}) =~ s/\s/_/g;
	$fname =~ s/\W//g;
	open(my $fh, ">", "out/$fname.txt") or die $!;
	print $fh $desc;
	close $fh;
}

my %library = (
	id => "LIBRARY",
	name => "My Saved Songs",
	owner => {
		display_name => $user
	}
);

mkdir "out" or die $! unless -e "out";

my @playlists = get_playlists();
foreach my $p (\%library, @playlists) {
	print("Processing $p->{name}\n");
	writep($p);
}


exit 0;
