<?php
require 'vendor/autoload.php'; // Include the JWT library
require_once("../config/database.php");
require_once("lti.php");
require_once("lib.php");

use Firebase\JWT\JWT;

$lti = new LTI();
$typeid = $_REQUEST['id'];
$courseid = $_REQUEST['course'];

$jwt = $_REQUEST['JWT'];

if (!empty($jwt)) {
    $params = lti_convert_from_jwt($typeid, $jwt);
    $consumerkey = $params['oauth_consumer_key'] ?? '';
    $messagetype = $params['lti_message_type'] ?? '';
    $version = $params['lti_version'] ?? '';
    $items = $params['content_items'] ?? '';
    $errormsg = $params['lti_errormsg'] ?? '';
    $msg = $params['lti_msg'] ?? '';
}

if (empty($errormsg) && !empty($items)) {
    try {
        $returndata = lti_tool_configuration_from_content_item($typeid, $messagetype, $version, $consumerkey, $items);
    } catch (Exception $e) {
        $errormsg = $e->getMessage();
    }
}
// var_dump($returndata);

?>
<input type='hidden' id='content_return_data' value='<?php echo json_encode($returndata); ?>'>
<?php // Add messages to notification stack for rendering later.
if ($errormsg) {
    // Show error message and exit the modal
    echo "error";
} else if (!empty($returndata)) {
    // Show success message and exit the modal
    echo "success";
}

/**
 * Verfies the JWT and converts its claims to their equivalent message parameter.
 *
 * @param int    $typeid
 * @param string $jwtparam   JWT parameter
 *
 * @return array  message parameters
 * @throws Exception
 */
function lti_convert_from_jwt($typeid, $jwtparam)
{
    $params = array();
    $parts = explode('.', $jwtparam);
    $ok = (count($parts) === 3);
    if ($ok) {
        $payload = JWT::urlsafeB64Decode($parts[1]);
        $claims = json_decode($payload, true);
        $ok = !is_null($claims) && !empty($claims['iss']);
    }
    if ($ok) {
        //Tip: Take care in next version (Similar to token.php)
        //lti_verify_jwt_signature($typeid, $claims['iss'], $jwtparam);
        $params['oauth_consumer_key'] = $claims['iss'];
        foreach (lti_get_jwt_claim_mapping() as $key => $mapping) {
            $claim = LTI_JWT_CLAIM_PREFIX;
            if (!empty($mapping['suffix'])) {
                $claim .= "-{$mapping['suffix']}";
            }
            $claim .= '/claim/';
            if (is_null($mapping['group'])) {
                $claim = $mapping['claim'];
            } else if (empty($mapping['group'])) {
                $claim .= $mapping['claim'];
            } else {
                $claim .= $mapping['group'];
            }
            if (isset($claims[$claim])) {
                $value = null;
                if (empty($mapping['group'])) {
                    $value = $claims[$claim];
                } else {
                    $group = $claims[$claim];
                    if (is_array($group) && array_key_exists($mapping['claim'], $group)) {
                        $value = $group[$mapping['claim']];
                    }
                }
                if (!empty($value) && $mapping['isarray']) {
                    if (is_array($value)) {
                        if (is_array($value[0])) {
                            $value = json_encode($value);
                        } else {
                            $value = implode(',', $value);
                        }
                    }
                }
                if (!is_null($value) && is_string($value) && (strlen($value) > 0)) {
                    $params[$key] = $value;
                }
            }
            $claim = LTI_JWT_CLAIM_PREFIX . '/claim/custom';
            if (isset($claims[$claim])) {
                $custom = $claims[$claim];
                if (is_array($custom)) {
                    foreach ($custom as $key => $value) {
                        $params["custom_{$key}"] = $value;
                    }
                }
            }
            $claim = LTI_JWT_CLAIM_PREFIX . '/claim/ext';
            if (isset($claims[$claim])) {
                $ext = $claims[$claim];
                if (is_array($ext)) {
                    foreach ($ext as $key => $value) {
                        $params["ext_{$key}"] = $value;
                    }
                }
            }
        }
    }
    if (isset($params['content_items'])) {
        $params['content_items'] = lti_convert_content_items($params['content_items']);
    }
    $messagetypemapping = lti_get_jwt_message_type_mapping();
    if (isset($params['lti_message_type']) && array_key_exists($params['lti_message_type'], $messagetypemapping)) {
        $params['lti_message_type'] = $messagetypemapping[$params['lti_message_type']];
    }
    return $params;
}

/**
 * Converts the new Deep-Linking format for Content-Items to the old format.
 *
 * @param string $param JSON string representing new Deep-Linking format
 * @return string  JSON representation of content-items
 */
function lti_convert_content_items($param)
{
    $items = array();
    $json = json_decode($param);
    if (!empty($json) && is_array($json)) {
        foreach ($json as $item) {
            if (isset($item->type)) {
                $newitem = clone $item;
                switch ($item->type) {
                    case 'ltiResourceLink':
                        $newitem->{'@type'} = 'LtiLinkItem';
                        $newitem->mediaType = 'application\/vnd.ims.lti.v1.ltilink';
                        break;
                    case 'link':
                    case 'rich':
                        $newitem->{'@type'} = 'ContentItem';
                        $newitem->mediaType = 'text/html';
                        break;
                    case 'file':
                        $newitem->{'@type'} = 'FileItem';
                        break;
                }
                unset($newitem->type);
                if (isset($item->html)) {
                    $newitem->text = $item->html;
                    unset($newitem->html);
                }
                if (isset($item->iframe)) {
                    // DeepLinking allows multiple options to be declared as supported.
                    // We favor iframe over new window if both are specified.
                    $newitem->placementAdvice = new stdClass();
                    $newitem->placementAdvice->presentationDocumentTarget = 'iframe';
                    if (isset($item->iframe->width)) {
                        $newitem->placementAdvice->displayWidth = $item->iframe->width;
                    }
                    if (isset($item->iframe->height)) {
                        $newitem->placementAdvice->displayHeight = $item->iframe->height;
                    }
                    unset($newitem->iframe);
                    unset($newitem->window);
                } else if (isset($item->window)) {
                    $newitem->placementAdvice = new stdClass();
                    $newitem->placementAdvice->presentationDocumentTarget = 'window';
                    if (isset($item->window->targetName)) {
                        $newitem->placementAdvice->windowTarget = $item->window->targetName;
                    }
                    if (isset($item->window->width)) {
                        $newitem->placementAdvice->displayWidth = $item->window->width;
                    }
                    if (isset($item->window->height)) {
                        $newitem->placementAdvice->displayHeight = $item->window->height;
                    }
                    unset($newitem->window);
                } else if (isset($item->presentation)) {
                    // This may have been part of an early draft but is not in the final spec
                    // so keeping it around for now in case it's actually been used.
                    $newitem->placementAdvice = new stdClass();
                    if (isset($item->presentation->documentTarget)) {
                        $newitem->placementAdvice->presentationDocumentTarget = $item->presentation->documentTarget;
                    }
                    if (isset($item->presentation->windowTarget)) {
                        $newitem->placementAdvice->windowTarget = $item->presentation->windowTarget;
                    }
                    if (isset($item->presentation->width)) {
                        $newitem->placementAdvice->dislayWidth = $item->presentation->width;
                    }
                    if (isset($item->presentation->height)) {
                        $newitem->placementAdvice->dislayHeight = $item->presentation->height;
                    }
                    unset($newitem->presentation);
                }
                if (isset($item->icon) && isset($item->icon->url)) {
                    $newitem->icon->{'@id'} = $item->icon->url;
                    unset($newitem->icon->url);
                }
                if (isset($item->thumbnail) && isset($item->thumbnail->url)) {
                    $newitem->thumbnail->{'@id'} = $item->thumbnail->url;
                    unset($newitem->thumbnail->url);
                }
                if (isset($item->lineItem)) {
                    unset($newitem->lineItem);
                    $newitem->lineItem = new stdClass();
                    $newitem->lineItem->{'@type'} = 'LineItem';
                    $newitem->lineItem->reportingMethod = 'http://purl.imsglobal.org/ctx/lis/v2p1/Result#totalScore';
                    if (isset($item->lineItem->label)) {
                        $newitem->lineItem->label = $item->lineItem->label;
                    }
                    if (isset($item->lineItem->resourceId)) {
                        $newitem->lineItem->assignedActivity = new stdClass();
                        $newitem->lineItem->assignedActivity->activityId = $item->lineItem->resourceId;
                    }
                    if (isset($item->lineItem->tag)) {
                        $newitem->lineItem->tag = $item->lineItem->tag;
                    }
                    if (isset($item->lineItem->scoreMaximum)) {
                        $newitem->lineItem->scoreConstraints = new stdClass();
                        $newitem->lineItem->scoreConstraints->{'@type'} = 'NumericLimits';
                        $newitem->lineItem->scoreConstraints->totalMaximum = $item->lineItem->scoreMaximum;
                    }
                    if (isset($item->lineItem->submissionReview)) {
                        $newitem->lineItem->submissionReview = $item->lineItem->submissionReview;
                    }
                }
                $items[] = $newitem;
            }
        }
    }

    $newitems = new stdClass();
    $newitems->{'@context'} = 'http://purl.imsglobal.org/ctx/lti/v1/ContentItem';
    $newitems->{'@graph'} = $items;

    return json_encode($newitems);
}

/**
 * Processes the tool provider's response to the ContentItemSelectionRequest and builds the configuration data from the
 * selected content item. This configuration data can be then used when adding a tool into the course.
 *
 * @param int $typeid The tool type ID.
 * @param string $messagetype The value for the lti_message_type parameter.
 * @param string $ltiversion The value for the lti_version parameter.
 * @param string $consumerkey The consumer key.
 * @param string $contentitemsjson The JSON string for the content_items parameter.
 * @return stdClass The array of module information objects.
 * @throws Exception
 */
function lti_tool_configuration_from_content_item($typeid, $messagetype, $ltiversion, $consumerkey, $contentitemsjson)
{
    //Fetch LTI Types
    $lti = new LTI();
    $tool = new \stdClass();
    $stmt = $lti->get_lti_types($typeid);
    if ($result = $stmt->fetch(PDO::FETCH_ASSOC)) {
        $tool->lti_typename = $result['tool_name'];
        $tool->typeid = $result['lti_types_id'];
        $tool->lti_toolurl = $result['tool_url'];
        $tool->lti_ltiversion = $result['lti_version'];
        $tool->lti_clientid = $result['client_id'];
        $tool->toolproxyid = $result['tool_proxy_id'];
        $tool->lti_parameters = $result['parameter'];
    }
    // Validate parameters.
    if (!$tool) {
        throw new Exception('errortooltypenotfound', 'lti');
    }
    // Check lti_message_type. Show debugging if it's not set to ContentItemSelection.
    // No need to throw exceptions for now since lti_message_type does not seem to be used in this processing at the moment.
    if ($messagetype !== 'ContentItemSelection') {
        //debugging("lti_message_type is invalid: {$messagetype}. It should be set to 'ContentItemSelection'.",
        //DEBUG_DEVELOPER);
    }

    // Check LTI versions from our side and the response's side. Show debugging if they don't match.
    // No need to throw exceptions for now since LTI version does not seem to be used in this processing at the moment.
    $expectedversion = $tool->lti_ltiversion;
    if ($ltiversion !== $expectedversion) {
        //debugging("lti_version from response does not match the tool's configuration. Tool: {$expectedversion}," .
        //" Response: {$ltiversion}", DEBUG_DEVELOPER);
    }

    $items = json_decode($contentitemsjson);
    if (empty($items)) {
        throw new Exception('errorinvaliddata', 'lti');
    }
    if (!isset($items->{'@graph'}) || !is_array($items->{'@graph'})) {
        throw new Exception('errorinvalidresponseformat', 'mod_lti');
    }

    $config = null;
    $items = $items->{'@graph'};
    if (!empty($items)) {
        //Fetch LTI Types Config
        $stmt = $lti->get_lti_types_config($tool->typeid);
        // fetch values
        while ($result = $stmt->fetch(PDO::FETCH_ASSOC)) {
            $config[$result['name']] = $result['value'];
        }
        if (isset($config['publickeyset'])) {
            $tool->lti_publickeyset = $config['publickeyset'];
        }
        if (isset($config['keytype'])) {
            $tool->lti_keytype = $config['keytype'];
        }
        if (isset($config['initiatelogin'])) {
            $tool->lti_initiatelogin = $config['initiatelogin'];
        }
        if (isset($config['sendname'])) {
            $tool->lti_sendname = $config['sendname'];
        }
        if (isset($config['send_email_id'])) {
            $tool->lti_sendemailaddr = $config['send_email_id'];
        }
        if (isset($config['accept_grades'])) {
            $tool->lti_acceptgrades = $config['accept_grades'];
        }
        if (isset($config['customparameters'])) {
            $tool->lti_customparameters = $config['customparameters'];
        }
        if (isset($config['launchcontainer'])) {
            $tool->lti_launchcontainer = $config['launchcontainer'];
        }
        if (isset($config['content_item_selection_request'])) {
            $tool->lti_toolurl_ContentItemSelectionRequest = $config['content_item_selection_request'];
        }
        // $typeconfig = lti_get_type_type_config($tool->id);
        if (count($items) == 1) {
            $config = content_item_to_form($tool, $items[0]);
        } else {
            $multiple = [];
            foreach ($items as $item) {
                $multiple[] = content_item_to_form($tool, $item);
            }
            $config = new stdClass();
            $config->multiple = $multiple;
        }
    }
    return $config;
}

/**
 * Converts LTI 1.1 Content Item for LTI Link to Form data.
 *
 * @param object $tool Tool for which the item is created for.
 * @param object $typeconfig The tool configuration.
 * @param object $item Item populated from JSON to be converted to Form form
 *
 * @return stdClass Form config for the item
 */
function content_item_to_form(object $tool, object $item): stdClass
{
    $config = new stdClass();
    $config->name = '';
    if (isset($item->title)) {
        $config->name = $item->title;
    }
    if (empty($config->name)) {
        $config->name = $tool->name;
    }
    if (isset($item->text)) {
        $config->introeditor = [
            'text' => $item->text,
            'format' => FORMAT_PLAIN
        ];
    } else {
        $config->introeditor = [
            'text' => '',
            'format' => FORMAT_PLAIN
        ];
    }
    if (isset($item->icon->{'@id'})) {
        $iconurl = $item->icon->{'@id'};
        // Assign item's icon URL to secureicon or icon depending on its scheme.
        if (strtolower($iconurl->get_scheme()) === 'https') {
            $config->secureicon = $iconurl->out(false);
        } else {
            $config->icon = $iconurl->out(false);
        }
    }
    if (isset($item->url)) {
        $url = $item->url;
        $config->toolurl = $url;
        $config->typeid = $tool->typeid;
    } else {
        $config->typeid = $tool->typeid;
    }
    $config->instructorchoiceacceptgrades = LTI_SETTING_NEVER;
    if (isset($tool->lti_acceptgrades)) {
        $acceptgrades = $tool->lti_acceptgrades;
        if ($acceptgrades == LTI_SETTING_ALWAYS) {
            // We create a line item regardless if the definition contains one or not.
            $config->instructorchoiceacceptgrades = LTI_SETTING_ALWAYS;
            // $config->grade_modgrade_point = 100;
        }
        if ($acceptgrades == LTI_SETTING_DELEGATE || $acceptgrades == LTI_SETTING_ALWAYS) {
            if (isset($item->lineItem)) {
                $lineitem = $item->lineItem;
                $config->instructorchoiceacceptgrades = LTI_SETTING_ALWAYS;
                $maxscore = 100;
                if (isset($lineitem->scoreConstraints)) {
                    $sc = $lineitem->scoreConstraints;
                    if (isset($sc->totalMaximum)) {
                        $maxscore = $sc->totalMaximum;
                    } else if (isset($sc->normalMaximum)) {
                        $maxscore = $sc->normalMaximum;
                    }
                }
                //$config->grade_modgrade_point = $maxscore;
                $config->grade_point = $maxscore;
                $config->lineitemresourceid = '';
                $config->lineitemtag = '';
                $config->lineitemsubreviewurl = '';
                $config->lineitemsubreviewparams = '';
                if (isset($lineitem->assignedActivity) && isset($lineitem->assignedActivity->activityId)) {
                    $config->lineitemresourceid = $lineitem->assignedActivity->activityId ?: '';
                }
                if (isset($lineitem->tag)) {
                    $config->lineitemtag = $lineitem->tag ?: '';
                }
                if (isset($lineitem->submissionReview)) {
                    $subreview = $lineitem->submissionReview;
                    $config->lineitemsubreviewurl = 'DEFAULT';
                    if (!empty($subreview->url)) {
                        $config->lineitemsubreviewurl = $subreview->url;
                    }
                    if (isset($subreview->custom)) {
                        $config->lineitemsubreviewparams = params_to_string($subreview->custom);
                    }
                }
            }
        }
    }
    $config->instructorchoicesendname = LTI_SETTING_NEVER;
    $config->instructorchoicesendemailaddr = LTI_SETTING_NEVER;
    $config->launchcontainer = LTI_LAUNCH_CONTAINER_DEFAULT;
    if (isset($item->placementAdvice->presentationDocumentTarget)) {
        if ($item->placementAdvice->presentationDocumentTarget === 'window') {
            $config->launchcontainer = LTI_LAUNCH_CONTAINER_WINDOW;
        } else if ($item->placementAdvice->presentationDocumentTarget === 'frame') {
            $config->launchcontainer = LTI_LAUNCH_CONTAINER_EMBED_NO_BLOCKS;
        } else if ($item->placementAdvice->presentationDocumentTarget === 'iframe') {
            $config->launchcontainer = LTI_LAUNCH_CONTAINER_EMBED;
        }
    }
    if (isset($item->custom)) {
        $config->instructorcustomparameters = params_to_string($item->custom);
    }
    return $config;
}

/**
 * Converts an array of custom parameters to a new line separated string.
 *
 * @param object $params list of params to concatenate
 *
 * @return string
 */
function params_to_string(object $params)
{
    $customparameters = [];
    foreach ($params as $key => $value) {
        $customparameters[] = "{$key}={$value}";
    }
    return implode("\n", $customparameters);
}

?>