#  You may distribute under the terms of either the GNU General Public License
#  or the Artistic License (the same terms as Perl itself)
#
#  (C) Paul Evans, 2016 -- leonerd@leonerd.org.uk

package App::MatrixTool::Command::client;

use strict;
use warnings;
use base qw( App::MatrixTool::SubCommands );

our $VERSION = '0.05';

use constant DESCRIPTION => "commandline client utilities";
use constant OPTIONS => (
   's|server=s' => "Server",
   'u|user-id=s' => "User ID",
);

require JSON;
my $JSON = JSON->new->utf8(1)->pretty(1);

sub run
{
   my $self = shift;
   my ( $opts, @args ) = @_;

   $self->{$_} //= $opts->{$_} for qw( server user_id );

   return $self->SUPER::run( @args );
}

sub do_json
{
   my $self = shift;
   my ( $method, $path, %opts ) = @_;

   my $client = $self->http_client;

   if( my $user_id = $self->{user_id} ) {
      my ( $server ) = $user_id =~ m/^@.*?:(.*)$/;
      $self->{server} //= $server;
   }

   defined $self->{server} or
      die "Not sure what --server to use\n";

   if( $self->{server} && $self->{user_id} ) {
      my $token = $self->client_token_store->get(
         server => $self->{server},
         id     => $self->{user_id},
      );

      $opts{params}{access_token} = $token if defined $token;
   }

   $client->request_json(
      server => $self->{server},
      method => $method,
      path   => $path,
      %opts,
   );
}

package
   App::MatrixTool::Command::client::json;
use base qw( App::MatrixTool::Command::client );

use constant DESCRIPTION => "perform a direct JSON request";
use constant ARGUMENTS => ( "path", "data?" );
use constant OPTIONS => (
   'm|method=s' => "HTTP method",
);

sub run
{
   my $self = shift;
   my ( $opts, $pathquery, $data ) = @_;

   my $method = "GET";
   $method = "PUT" if defined $data;

   $method = $opts->{method} if defined $opts->{method};

   my %opts;

   $opts{content} = $JSON->decode( $data ) if defined $data;

   my $uri = URI->new( $pathquery );
   if( $uri->query_form ) {
      $opts{params} = { $uri->query_form };
   }

   $self->do_json( $method, $uri->path, %opts )->then( sub {
      my ( $body, $response ) = @_;

      print $JSON->encode( $body ) . "\n";
      Future->done();
   });
}

package
   App::MatrixTool::Command::client::login;
use base qw( App::MatrixTool::Command::client );

use constant DESCRIPTION => "obtain a client authentication token";
use constant ARGUMENTS => ( "user", "password?" );

sub run
{
   my $self = shift;
   my ( $opts, $user, $password ) = @_;

   $self->{user_id} = $user;

   if( !defined $password ) {
      require IO::Termios;
      my $stdin = IO::Termios->new( \*STDIN );

      STDOUT->autoflush(1);
      print "Password: ";

      $stdin->setflag_echo( 0 );
      $password = <$stdin>; chomp $password; print "\n";
      $stdin->setflag_echo( 1 );
   }

   $self->do_json( POST => "/_matrix/client/r0/login",
      content => {
         type => "m.login.password",
         user => $user,
         password => $password,
      }
   )->then( sub {
      my ( $body ) = @_;

      $self->client_token_store->put(
         server => $self->{server},
         id     => $user,
         data   => $body->{access_token},
      );

      $self->output_ok( "Obtained access token" );

      Future->done();
   });
}

package
   App::MatrixTool::Command::client::upload;
use base qw( App::MatrixTool::Command::client );

use File::Slurper qw( read_binary );

use constant ARGUMENTS => ( "file", "type?" );

sub run
{
   my $self = shift;
   my ( $opts, $file, $type ) = @_;

   my $content = read_binary( $file );

   unless( defined $type ) {
      $type = "image/jpeg" if $file =~ m/\.jp[e]?g$/;
      $type = "iamge/png"  if $file =~ m/\.png$/;

      defined $type or
         die "Type not specified and could not guess it from the filename\n";
   }

   $self->do_json( POST => "/_matrix/media/r0/upload",
      content => $content,
      content_type => $type,
   )->then( sub {
      my ( $result ) = @_;

      $self->output_ok( "Uploaded content" );

      print $result->{content_uri} . "\n";

      Future->done();
   });
}

0x55AA;
