<?php

declare(strict_types=1);

namespace Drupal\lms_xapi_activity;

use Drupal\Core\Cache\CacheableMetadata;
use Drupal\Core\Entity\EntityInterface;
use Drupal\Core\Routing\RouteMatchInterface;
use Drupal\Core\Session\AccountInterface;
use Drupal\lms\Entity\Bundle\Course;
use Drupal\lms\TrainingManager;
use Drupal\lms_xapi\XapiIdGeneratorInterface;
use Drupal\lms\Entity\ActivityInterface;
use Drupal\lms\Entity\ActivityTypeInterface;
use Drupal\lms\Entity\AnswerInterface;
use Drupal\lms\Entity\CourseStatusInterface;

/**
 * Xapi LRS event subscriber.
 */
final class ActivityXapiIdGenerator implements XapiIdGeneratorInterface {

  /**
   * Constructor.
   */
  public function __construct(
    private readonly RouteMatchInterface $routeMatch,
    private readonly TrainingManager $trainingManager,
  ) {}

  /**
   * {@inheritdoc}
   */
  public function applies(
    EntityInterface $entity,
    AccountInterface $student,
    CacheableMetadata $cacheable_metadata,
  ): bool {
    if (!$entity instanceof ActivityInterface) {
      return FALSE;
    }
    $cacheable_metadata->setCacheContexts($cacheable_metadata->getCacheContexts() + ['route']);
    $course_status = $this->getCourseStatus($student);
    if ($course_status === NULL) {
      return FALSE;
    }
    $cacheable_metadata->addCacheableDependency($course_status);

    $bundle = $entity->get('type')->entity;
    assert($bundle instanceof ActivityTypeInterface);
    $plugin = $bundle->getPluginId();
    if ($plugin !== 'xapi') {
      return FALSE;
    }

    return TRUE;
  }

  /**
   * {@inheritdoc}
   */
  public function generate(
    EntityInterface $entity,
    AccountInterface $student,
    CacheableMetadata $cacheable_metadata,
  ): array {
    $course_status = $this->getCourseStatus($student);
    if ($course_status === NULL) {
      throw new \Exception('Unable to determine the current course status.');
    }

    return [
      $entity->getEntityTypeId(),
      $entity->id(),
      $course_status->id(),
    ];
  }

  /**
   * Get the current course status from route.
   */
  private function getCourseStatus(AccountInterface $student): ?CourseStatusInterface {
    $course = $this->routeMatch->getParameter('group');
    if (!$course instanceof Course) {
      // This may be an answer details route.
      $answer = $this->routeMatch->getParameter('lms_answer');
      if (!$answer instanceof AnswerInterface) {
        return NULL;
      }
      return $answer->getLessonStatus()->getCourseStatus();
    }
    else {
      return $this->trainingManager->loadCourseStatus($course, $student, [
        'current' => TRUE,
      ]);
    }
  }

}
