<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;
use \Illuminate\Contracts\View\View;
use App\Http\Requests\LtiLoginInitiation;
use Illuminate\Support\Facades\Log;
use App\Helpers\DataStructure\OnLaunchData;
use App\Helpers\Lti\Lti;
use App\Helpers\Lti\LtiContent;
use App\Models\ResourceLink;
use App\Models\Platform;
use App\Models\Nonce;
use App\Models\Context;
use App\Models\User;

class LtiAuthBaseController extends Controller
{
    public function onLaunch(OnLaunchData $data) {
        return View('lti.helloWorldLti', ["data" => $data]);
    }

    public function connect(LtiLoginInitiation $request) {
        if(Lti::isLoginHint($request)){
            Log::debug("[LtiAuthBaseController] Lti login Hint request",
            $request->only(['iss', 'client_id']));
            return $this->attemptLogin($request);
        }else if(Lti::isLtiToken($request)){
            Log::debug("[LtiAuthBaseController] Successful login",
            $request->only(['id_token', 'state']));
            $lti = new Lti($request->id_token, $request->state);
            $ltiContent = $lti->getContent();
            $platform = $lti->getPlatform();
            $platform = $this->updatePlatform($ltiContent, $platform);
            $user = $this->updateOrCreateUser($ltiContent, $platform->id);
            $context = $this->updateOrCreateContext($ltiContent, $platform->id);
            $resourceLink = $this->updateOrCreateResourceLink($ltiContent, $context);
            $data = new OnLaunchData();
            $data->platform = $platform;
            $data->context = $context;
            $data->resourceLink = $resourceLink;
            $data->user = $user;
            return $this->onLaunch($data);
        }else{
            Log::warning("[LtiAuthBaseController] Connect route receive incorrect params",
            $request->all());
            return abort(401);
        }
    }

    private function attemptLogin (LtiLoginInitiation $request) : View {
        $platformQuery = ["issuer_id" => $request->iss, "client_id" => $request->client_id];
        $platform = Platform::where($platformQuery)->firstOrFail();
        $nonce = Nonce::create(['platform_id' => $platform->id]);
        $viewParams = ['url' => $platform->authentication_url,
                       'params' => array(
                            'client_id' => $platform->client_id,
                            'login_hint' => $request->login_hint,
                            'lti_message_hint' => $request->lti_message_hint,
                            'nonce' => $nonce->value,
                            'prompt' => 'none',
                            'redirect_uri' => route('lti.connect'),
                            'response_mode' => 'form_post',
                            'response_type' => 'id_token',
                            'scope' => 'openid',
                            'state' => $nonce->value
                       )
                ];
        Log::debug("[LtiAuthBaseController] Attempt login for platform id: {$platform->id}", $viewParams);
        return View('lti.autoSubmitForm', $viewParams);
    }

    private function updatePlatform(LtiContent $content, Platform $platform) : Platform {
        Log::debug('[LtiAuthBaseController] Starting updating Platform');
        $platform->guid = $content->getClaims()->tool_platform->guid;
        $platform->name = $content->getClaims()->tool_platform->name;
        $platform->version = $content->getClaims()->tool_platform->version;
        $platform->product_family_code = $content->getClaims()->tool_platform->product_family_code;
        $platform->validation_context = $content->getClaims()->tool_platform->validation_context;
        $platform->target_link_uri = $content->getClaims()->target_link_uri;
        $platform->update();
        Log::debug('[LtiAuthBaseController] Platform has been updated successfully');
        return $platform;
    }

    private function updateOrCreateUser(LtiContent $content, int $platform_id) : User {
        Log::debug('[LtiAuthBaseController] Starting updating or creating User');
        $fields = [
            'name' => $content->getUserName(),
            'given_name' => $content->getUserGivenName(),
            'family_name' => $content->getUserFamilyName(),
            'email' => $content->getUserEmail(),
            'picture' => $content->getUserPicture(),
            'roles' => implode(" ", $content->getClaims()->roles),
            'person_sourceid' => $content->getClaims()->lis->person_sourcedid,
        ];
        $conditions = ['lti_id' => $content->getUserId(), 'platform_id' => $platform_id];
        $user = User::updateOrCreate($conditions, $fields);
        Log::debug('[LtiAuthBaseController] User has been updated or created successfully');
        return $user;
    }
    private function updateOrCreateContext(LtiContent $content, int $platform_id) : Context {
        Log::debug('[LtiAuthBaseController] Starting updating or creating Context');
        $fields = [
            'label' => $content->getClaims()->context->label,
            'title' => $content->getClaims()->context->title,
            'type' => implode(" ", $content->getClaims()->context->type)
        ];
        $conditions = ['lti_id' => $content->getClaims()->context->id,'platform_id' => $platform_id];
        $context = Context::updateOrCreate($conditions, $fields);
        Log::debug('[LtiAuthBaseController] Context has been updated or created successfully');
        return $context;
    }

    private function updateOrCreateResourceLink(LtiContent $content, Context $context) : ResourceLink {
        Log::debug('[LtiAuthBaseController] Starting updating or creating ResourceLink');
        $fields = [
            'description' => $content->getClaims()->resource_link->description,
            'title' => $content->getClaims()->resource_link->title,
            'validation_context' => $content->getClaims()->resource_link->validation_context
        ];
        $lti_id = $content->getClaims()->resource_link->id;
        $conditions = ['lti_id' => $lti_id, 'context_id' => $context->id];
        $resourceLink = ResourceLink::updateOrCreate($conditions, $fields);
        Log::debug('[LtiAuthBaseController] ResourceLink has been updated or created successfully');
        return $resourceLink;
    }


}
