# Copyright (C) Innuos
# SPDX-License-Identifier: GPL-2.0

package Plugins::PluginManagerAPI::Plugin;



use Slim::Utils::Log;
use Data::Dumper;

use Router::Simple;

use Plugins::PluginManagerAPI::Utilities;
use Plugins::PluginManagerAPI::Controllers::Plugins;
use Plugins::PluginManagerAPI::Controllers::Server;



my $log = Slim::Utils::Log->addLogCategory(
	{
		'category'     => 'plugin.PluginManagerAPI',
		'defaultLevel' => 'WARN',
		'description'  => getDisplayName(),
	}
);

my $router = Router::Simple->new();

#set up route matching rules
#implemented
$router->connect( '/plugins', { controller => 'plugins', action => 'getAllPlugins' }, {method => 'GET'} );			
$router->connect( '/plugins/enabled/{pluginid}', { controller => 'plugins', action => 'installPlugin' }, {method => 'POST'} );
$router->connect( '/plugins/enabled/{pluginid}', { controller => 'plugins', action => 'uninstallPlugin' }, {method => 'DELETE'} );
$router->connect( '/plugins/enabled/{pluginid}/delete', { controller => 'plugins', action => 'uninstallPlugin' }, {method => 'POST'} );
$router->connect( '/plugins/enabled', { controller => 'plugins', action => 'getEnabledPlugins' }, {method => 'GET'} );
$router->connect( '/plugins/enabled/{pluginid}', { controller => 'plugins', action => 'getPluginDetails' }, {method => 'GET'} );
$router->connect( '/server/pendingstatus', { controller => 'server', action => 'pendingStatus' }, {method => 'GET'} );
$router->connect( '/server/restart', { controller => 'server', action => 'restart' }, {method => 'POST'} );


my %controllerMap = (
	'plugins' => {
		'getEnabledPlugins' => \&Plugins::PluginManagerAPI::Controllers::Plugins::getEnabledPlugins,
		'getPluginDetails' 	=> \&Plugins::PluginManagerAPI::Controllers::Plugins::getPluginDetails,
		'getAllPlugins' 	=> \&Plugins::PluginManagerAPI::Controllers::Plugins::getAllPlugins,
		'installPlugin' 	=> \&Plugins::PluginManagerAPI::Controllers::Plugins::installPlugin,
		'uninstallPlugin' 	=> \&Plugins::PluginManagerAPI::Controllers::Plugins::uninstallPlugin,
		
	},
	'server' => {
		'restart' 		=> \&Plugins::PluginManagerAPI::Controllers::Server::restart,
		'pendingStatus' => \&Plugins::PluginManagerAPI::Controllers::Server::pendingStatus,
	}
);


sub initPlugin {
	my $class = shift;

	Slim::Web::Pages->addRawFunction('pmAPI/', \&handleRESTCall);

	return;
}


sub handleRESTCall {
	my ($httpClient, $httpResponse) = @_;

	my $req = $httpResponse->request;

	#Extract the route
	my $path = $req->uri->path;
	$path =~ s/^\/pmAPI//;

	#set up the PSGI type $env that the router requires
	my $env = {
		'REQUEST_METHOD' => $req->method,
		'PATH_INFO'		 => $path
	};

	main::DEBUGLOG && $log->is_debug && $log->debug("PSGI ENV " . Dumper($env));

	if ( my $match = $router->match($env) ) {
		main::DEBUGLOG && $log->is_debug && $log->debug("Route Matched :"  . Dumper($match));

		#Get the Controller Method
		my $controllerSub = $controllerMap{$match->{controller}}{$match->{action}};

		if ( defined $controllerSub ) {

			#Create the call back for writing the response
			my $cb = sub {
				my ($responseCode, $body) = @_;

				Plugins::PluginManagerAPI::Plugin::writeRESTResponse( $httpClient, $httpResponse, $responseCode, $body );
			};

			#call the controller operation
			eval { $controllerSub->( $match, $req->content(), $cb ) };
			if ($@) {

				# The controller fell over for some unknown reason
				$log->error("API Controller operation failed : $@");
				my $json =  Plugins::PluginManagerAPI::Utilities::encodeErrorMessageJSON('Internal System Error');
				Plugins::PluginManagerAPI::Plugin::writeRESTResponse($httpClient, $httpResponse, Plugins::PluginManagerAPI::Utilities::HTTP_INTERNAL_SERVER_ERROR, $json );
			}
	} else {

		my $json =  Plugins::PluginManagerAPI::Utilities::encodeErrorMessageJSON('Not yet implemented');
		Plugins::PluginManagerAPI::Plugin::writeRESTResponse($httpClient, $httpResponse, Plugins::PluginManagerAPI::Utilities::HTTP_METHOD_NOT_ALLOWED, $json );
	}
} else {
	main::DEBUGLOG && $log->is_debug && $log->debug("Route NOT Matched : $path ");

	my $json =  Plugins::PluginManagerAPI::Utilities::encodeErrorMessageJSON('No such operation');
	Plugins::PluginManagerAPI::Plugin::writeRESTResponse( $httpClient, $httpResponse, Plugins::PluginManagerAPI::Utilities::HTTP_NOT_FOUND, $json );
}

return;
}


sub writeRESTResponse {
	my ($httpClient, $httpResponse, $responseCode, $body) = @_;

	$httpResponse->code($responseCode);
	$httpResponse->header( 'Content-Type' => 'application/json' );
	$httpResponse->header( 'Content-Length', length $body );

	Slim::Web::HTTP::addHTTPResponse( $httpClient, $httpResponse, \$body);

	return;
}


sub getDisplayName { return 'PLUGIN_PLUGINMANAGERAPI'; }

1;
