Proyectos de Subversion LeadersLinked - Services

Rev

Rev 597 | Rev 633 | Ir a la última revisión | Autoría | Comparar con el anterior | Ultima modificación | Ver Log |

<?php
declare(strict_types=1);

namespace LeadersLinked\Controller;

use Laminas\Mvc\Controller\AbstractActionController;
use Laminas\View\Model\JsonModel;
use LeadersLinked\Library\Functions;
use LeadersLinked\Mapper\MicrolearningCapsuleMapper;
use LeadersLinked\Mapper\QueryMapper;
use LeadersLinked\Mapper\UserMapper;
use Laminas\Db\Sql\Select;
use LeadersLinked\Mapper\MicrolearningCapsuleUserMapper;
use LeadersLinked\Mapper\MicrolearningCapsuleCommentMapper;
use LeadersLinked\Form\Service\CapsuleCommentForm;
use LeadersLinked\Model\MicrolearningCapsuleComment;
use LeadersLinked\Model\MicrolearningCapsuleUser;
use LeadersLinked\Model\MicrolearningAnswer;
use LeadersLinked\Mapper\MicrolearningUserProgressMapper;
use LeadersLinked\Mapper\MicrolearningSlideMapper;
use LeadersLinked\Mapper\MicrolearningUserLogMapper;
use LeadersLinked\Model\MicrolearningUserLog;
use LeadersLinked\Mapper\MicrolearningTopicMapper;
use LeadersLinked\Mapper\CompanyMapper;
use LeadersLinked\Model\MicrolearningUserProgress;
use LeadersLinked\Mapper\MicrolearningExtendUserMapper;
use LeadersLinked\Mapper\MicrolearningExtendUserCompanyMapper;
use LeadersLinked\Mapper\MicrolearningExtendUserFunctionMapper;
use LeadersLinked\Mapper\MicrolearningExtendUserGroupMapper;
use LeadersLinked\Mapper\MicrolearningExtendUserInstitutionMapper;
use LeadersLinked\Mapper\MicrolearningExtendUserPartnerMapper;
use LeadersLinked\Mapper\MicrolearningExtendUserProgramMapper;
use LeadersLinked\Mapper\MicrolearningExtendUserStudentTypeMapper;
use LeadersLinked\Mapper\MicrolearningExtendUserSectorMapper;
use LeadersLinked\Mapper\MicrolearningQuizMapper;
use LeadersLinked\Mapper\MicrolearningQuestionMapper;
use LeadersLinked\Mapper\MicrolearningAnswerMapper;
use LeadersLinked\Model\MicrolearningSlide;
use LeadersLinked\Library\Storage;
use LeadersLinked\Mapper\MicrolearningTopicCapsuleMapper;


class MicrolearningUserAccessGrantedIds
{
    public $companies;
    public $topics;
    public $capsules; 
    
    
    public function __construct()
    {
        $this->companies    = [];
        $this->topics       = [];
        $this->capsules     = [];
    }
}

class MicrolearningController extends AbstractActionController
{
    
    /**
     *
     * @var \Laminas\Db\Adapter\AdapterInterface
     */
    private $adapter;
    
    /**
     *
     * @var \LeadersLinked\Cache\CacheInterface
     */
    private $cache;
    
    
    /**
     *
     * @var \Laminas\Log\LoggerInterface
     */
    private $logger;
    
    /**
     *
     * @var array
     */
    private $config;
    
    
    /**
     *
     * @var \Laminas\Mvc\I18n\Translator
     */
    private $translator;
    
    
    /**
     *
     * @param \Laminas\Db\Adapter\AdapterInterface $adapter
     * @param \LeadersLinked\Cache\CacheInterface $cache
     * @param \Laminas\Log\LoggerInterface LoggerInterface $logger
     * @param array $config
     * @param \Laminas\Mvc\I18n\Translator $translator
     */
    public function __construct($adapter, $cache, $logger, $config, $translator)
    {
        $this->adapter      = $adapter;
        $this->cache        = $cache;
        $this->logger       = $logger;
        $this->config       = $config;
        $this->translator   = $translator;
    }
    
    public function indexAction()
    {
        $request = $this->getRequest();
        
        if($request->isGet()) {
            return new JsonModel([
                'success' => true,
                'data' =>  [
                    'link_companies' => $this->url()->fromRoute('microlearning/companies',[], ['force_canonical' => true]),
                    'link_timeline' => $this->url()->fromRoute('microlearning/timeline',[], ['force_canonical' => true]),
                    'link_last_capsule_in_progress' => $this->url()->fromRoute('microlearning/last-capsule-in-progress',[], ['force_canonical' => true]),
                    'link_profile' => $this->url()->fromRoute('microlearning/profile',[], ['force_canonical' => true]),
                    'link_topics' => $this->url()->fromRoute('microlearning/topics',[], ['force_canonical' => true]),
                    'link_capsules_pending' => $this->url()->fromRoute('microlearning/capsules-pending',[], ['force_canonical' => true]),
                    'link_capsules_completed' => $this->url()->fromRoute('microlearning/capsules-completed',[], ['force_canonical' => true]),
                    'link_capsules_in_progress' => $this->url()->fromRoute('microlearning/capsules-in-progress',[], ['force_canonical' => true]),
                  

                ]
            ]);
        }
        
        return new JsonModel([
            'success' => false,
            'data' => 'ERROR_METHOD_NOT_ALLOWED'
        ]);
    }
        
    public function companiesAction()
    {

        $request = $this->getRequest();
        
        if($request->isGet()) {
            $currentNetworkPlugin = $this->plugin('currentNetworkPlugin');
            $currentNetwork = $currentNetworkPlugin->getNetwork();
            
            
            $accessGrantedIds = $this->getAccessGranted();
            $companyMapper = CompanyMapper::getInstance($this->adapter);
            $records = $companyMapper->fetchAllByIdsAndNetworkId($accessGrantedIds->companies, $currentNetwork->id);
            
            $storage = Storage::getInstance($this->config, $this->adapter);
            
            $companies = [];
            foreach($records as $record)
            {
                array_push($companies, [
                    'uuid' => $record->uuid,
                    'name' => $record->name, 
                    'image' => $storage->getCompanyImage($record),
                    'link_progress' => $this->url()->fromRoute('microlearning/progress',['id' => $record->uuid], ['force_canonical' => true]),
                ]);
            }
            
            return new JsonModel([
                'success' => true,
                'data' =>  $companies
            ]);
            
            
        }
        return new JsonModel([
            'success' => false,
            'data' => 'ERROR_METHOD_NOT_ALLOWED'
        ]);
    }

    public function capsuleCommentsAction()
    {
        
        $request = $this->getRequest();
        
        if($request->isGet()) {
            $serviceDatetimeFormat = $this->config['leaderslinked.services.datetime'];
            
            $currentUserPlugin = $this->plugin('currentUserPlugin');
            $currentUser = $currentUserPlugin->getUser();
            
            $capsule_id = $this->params()->fromRoute('capsule_id');
            
            $capsuleMapper = MicrolearningCapsuleMapper::getInstance($this->adapter);
            $capsule = $capsuleMapper->fetchOneByUuid($capsule_id);
            
            if(!$capsule) {
                return new JsonModel([
                    'success' => false,
                    'data' => 'ERROR_CAPSULE_NOT_FOUND'
                    
                ]);
                
            }
            
            $capsuleUserMapper = MicrolearningCapsuleUserMapper::getInstance($this->adapter);
            $capsuleUser = $capsuleUserMapper->fetchOneByUserIdAndCapsuleId($currentUser->id, $capsule->id);
            if(! $capsuleUser) {
                return new JsonModel([
                    'success' => false,
                    'data' => 'ERROR_YOU_DO_NOT_HAVE_ACCESS_TO_THIS_CAPSULE',
                ]);
            }
            
            $userMapper = UserMapper::getInstance($this->adapter);
            $users = [];
            
            
            $storage = Storage::getInstance($this->config, $this->adapter);
            
            $capsuleCommentMapper = MicrolearningCapsuleCommentMapper::getInstance($this->adapter);
            $records = $capsuleCommentMapper->fetchAllByCapsuleId($capsule->id);
            
            $comments = [];
            foreach($records as $record)
            {
                
                if(isset($users[$record->user_id])) {
                    
                    $user = $users[$record->user_id];
                    
                } else {
                    
                    $user = $userMapper->fetchOne($record->user_id);
                    if(!$user) {
                        continue;
                    }
                    
                    $users[$record->user_id] = $user;
                    
                    
                }
                
                
                $dt = \DateTime::createFromFormat('Y-m-d H:i:s', $record->added_on);
                
                array_push($comments, [
                    'date' => $dt->format($serviceDatetimeFormat),
                    'image' => $storage->getUserImage($user),
                    'fullname' => trim(trim($user->first_name) . ' ' . trim($user->last_name)),
                    'rating' => strval($record->rating),
                    'comment' => $record->comment,
                    'link_delete' => $record->user_id == $currentUser->id ? $this->url()->fromRoute('microlearning/capsules-comments/delete', ['capsule_id' => $capsule->uuid, 'comment_id' => $record->uuid], ['force_canonical' => true]) : '',
                ]);
            }
            
            $dataCountAndRatingAverage = $capsuleCommentMapper->fetchCountAndRatingAverage($capsule->company_id, $capsule->id);
            
            return new JsonModel([
                'success' => true,
                'data' => [
                    'comments' => $comments,
                    'capsule' => [
                        'total_comments' => strval($dataCountAndRatingAverage['total_comments']),
                        'total_rating' => strval($dataCountAndRatingAverage['total_rating'])
                    ]
                ]
                
            ]);
            
        }
        
        return new JsonModel([
            'success' => false,
            'data' => 'ERROR_METHOD_NOT_ALLOWED'
        ]);
    }
    
    
    
    public function capsuleDeleteMyCommentAction()
    {
        
        $request = $this->getRequest();
        
        if($request->isPost()) {
            
            $currentUserPlugin = $this->plugin('currentUserPlugin');
            $currentUser = $currentUserPlugin->getUser();
            
            $capsule_id = $this->params()->fromRoute('capsule_id');
            $comment_id = $this->params()->fromRoute('comment_id');
            
            $capsuleMapper = MicrolearningCapsuleMapper::getInstance($this->adapter);
            $capsule = $capsuleMapper->fetchOneByUuid($capsule_id);
            
            if(!$capsule) {
                return new JsonModel([
                    'success' => false,
                    'data' => 'ERROR_CAPSULE_NOT_FOUND'
                    
                ]);
                
            }
            
            $capsuleUserMapper = MicrolearningCapsuleUserMapper::getInstance($this->adapter);
            $capsuleUser = $capsuleUserMapper->fetchOneByUserIdAndCapsuleId($currentUser->id, $capsule->id);
            if(! $capsuleUser) {
                return new JsonModel([
                    'success' => false,
                    'data' => 'ERROR_YOU_DO_NOT_HAVE_ACCESS_TO_THIS_CAPSULE',
                ]);
            }
            
            $capsuleCommentMapper = MicrolearningCapsuleCommentMapper::getInstance($this->adapter);
            $capsuleComment = $capsuleCommentMapper->fetchOneByUuid($comment_id);
            
            if(!$capsuleComment) {
                return new JsonModel([
                    'success' => false,
                    'data' => 'ERROR_CAPSULE_COMMENT_NOT_FOUND',
                ]);
            }
            
            if($capsuleComment->capsule_id != $capsule->id || $capsuleComment->user_id != $currentUser->id) {
                return new JsonModel([
                    'success' => false,
                    'data' => 'ERROR_YOU_DO_NOT_HAVE_ACCESS_TO_THIS_CAPSULE_COMMENT',
                ]);
            }
            
            
            $result = $capsuleCommentMapper->delete($capsuleComment->id);
            if($result) {
                $dataCountAndRatingAverage = $capsuleCommentMapper->fetchCountAndRatingAverage($capsule->company_id, $capsule->id);
                
                
                
                
                return new JsonModel([
                    'success' => true,
                    'data' => [
                        'message' => 'LABEL_CAPSULE_COMMENT_HAVE_BEEN_SUCCESSFULLY_DELETE',
                        'capsule' => [
                            'total_comments' => strval($dataCountAndRatingAverage['total_comments']),
                            'total_rating' => strval($dataCountAndRatingAverage['total_rating'])
                        ]
                    ],
                    
                ]);
            } else {
                return new JsonModel([
                    'success' => false,
                    'data' => $capsuleCommentMapper->getError()
                    
                ]);
            }
            
            
            
        }
        
        return new JsonModel([
            'success' => false,
            'data' => 'ERROR_METHOD_NOT_ALLOWED'
        ]);
    }
    
    public function capsuleAddMyCommentAction()
    {
        
        $request = $this->getRequest();
        
        if($request->isPost()) {
            
            $currentUserPlugin = $this->plugin('currentUserPlugin');
            $currentUser = $currentUserPlugin->getUser();
            
            $capsule_id = $this->params()->fromRoute('capsule_id');
            
            
            $capsuleMapper = MicrolearningCapsuleMapper::getInstance($this->adapter);
            $capsule = $capsuleMapper->fetchOneByUuid($capsule_id);
            
            if(!$capsule) {
                return new JsonModel([
                    'success' => false,
                    'data' => 'ERROR_CAPSULE_NOT_FOUND'
                    
                ]);
                
            }
            
            $capsuleUserMapper = MicrolearningCapsuleUserMapper::getInstance($this->adapter);
            $capsuleUser = $capsuleUserMapper->fetchOneByUserIdAndCapsuleId($currentUser->id, $capsule->id);
            if(! $capsuleUser) {
                return new JsonModel([
                    'success' => false,
                    'data' => 'ERROR_YOU_DO_NOT_HAVE_ACCESS_TO_THIS_CAPSULE',
                ]);
            }
            
            //$rawdata = file_get_contents("php://input");
            //  error_log('$rawdata = ' . $rawdata );
            
            
            $form = new  CapsuleCommentForm();
            $dataPost = $request->getPost()->toArray();
            $dataPost['added_on'] = $capsuleMapper->getDatebaseNow();

            
            $form->setData($dataPost);
            
            if($form->isValid()) {
                $dataPost = (array) $form->getData();
                
                
                $capsuleComment = new MicrolearningCapsuleComment();
                $capsuleComment->company_id = $capsule->company_id;
                $capsuleComment->capsule_id = $capsule->id;
                $capsuleComment->user_id = $currentUser->id;
                $capsuleComment->comment = $dataPost['comment'];
                $capsuleComment->rating = strval($dataPost['rating']);
                $capsuleComment->added_on =  $dataPost['added_on'];
                
                
                $capsuleCommentMapper = MicrolearningCapsuleCommentMapper::getInstance($this->adapter);
                $result = $capsuleCommentMapper->insert($capsuleComment);
                if($result) {
                    
                    $capsuleComment = $capsuleCommentMapper->fetchOne($capsuleComment->id);
                    
                    $dataCountAndRatingAverage = $capsuleCommentMapper->fetchCountAndRatingAverage($capsule->company_id,  $capsule->id);
                    
                    
                    
                    return new JsonModel([
                        'success' => true,
                        'data' => [
                            'message' =>'LABEL_CAPSULE_COMMENT_HAVE_BEEN_SUCCESSFULLY_ADDED',
                            
                            'comment' => [
                                'comment' => $capsuleComment->comment,
                                'rating' => $capsuleComment->rating,
                                'link_delete' => $this->url()->fromRoute('microlearning/capsules-comments/delete', ['capsule_id' => $capsule->uuid, 'comment_id' => $capsuleComment->uuid], ['force_canonical' => true])
                            ],
                            'capsule' => [
                                'total_comments' => strval($dataCountAndRatingAverage['total_comments']),
                                'total_rating' => strval($dataCountAndRatingAverage['total_rating'])
                            ]
                        ]
                        
                    ]);
                } else {
                    return new JsonModel([
                        'success' => false,
                        'data' => $capsuleCommentMapper->getError()
                        
                    ]);
                }
                
                
            } else {
                $messages = [];
                $form_messages = (array) $form->getMessages();
                foreach($form_messages  as $fieldname => $field_messages)
                {
                    
                    $messages[$fieldname] = array_values($field_messages);
                }
                
                return new JsonModel([
                    'success'   => false,
                    'data'   => $messages
                ]);
            }
            
            
            
            
        }
        
        return new JsonModel([
            'success' => false,
            'data' => 'ERROR_METHOD_NOT_ALLOWED'
        ]);
    }
    
    public function lastCapsuleInProgressAction()
    {
        $request = $this->getRequest();
        
        if($request->isGet()) 
        {
            $currentUserPlugin = $this->plugin('currentUserPlugin');
            $currentUser = $currentUserPlugin->getUser();
            
            $accessGrantedIds = $this->getAccessGranted();
            
            
            $userProgressMapper = MicrolearningUserProgressMapper::getInstance($this->adapter);
            $userProgress = $userProgressMapper->fetchOneLastCapsuleInProgressByUserIdAndCapsuleIds($currentUser->id, $accessGrantedIds->capsules);
            $topicMapper = MicrolearningTopicMapper::getInstance($this->adapter);
            
            if($userProgress) {
                $storage = Storage::getInstance($this->config, $this->adapter);
                $path = $storage->getPathMicrolearningCapsule();
                
                $capsuleMapper = MicrolearningCapsuleMapper::getInstance($this->adapter);
                $capsule = $capsuleMapper->fetchOne($userProgress->capsule_id);
                
                $topic = $topicMapper->fetchOne($userProgress->topic_id);
                
                $capsuleCommentMapper = MicrolearningCapsuleCommentMapper::getInstance($this->adapter);
                $dataCountAndRatingAverage = $capsuleCommentMapper->fetchCountAndRatingAverage($capsule->company_id,  $capsule->id);
                $image = $storage->getGenericImage($path, $topic->uuid, $capsule->image);
            
                $response = [
                    'success' => true,
                    'data' => [
                        'uuid'              => $capsule->uuid,
                        'name'              => $capsule->name ? $capsule->name : '',
                        'description'       => $capsule->description ? $capsule->description : '',
                        'image'             => ($capsule->image && $topic) ? $storage->getGenericImage($path,  $topic->uuid, $capsule->image )  : '',
                        'total_comments'    => strval($dataCountAndRatingAverage['total_comments']),
                        'total_rating'      => strval($dataCountAndRatingAverage['total_rating']),
                        'completed'         => $userProgress->completed,
                        'progress'          => $userProgress->progress,
                        'added_on'          => $userProgress->added_on,
                        'updated_on'        => $userProgress->updated_on
                    ] 
                ];
                
                
            } else {
                $response = [
                    'success' => true, 
                    'data' => []
                ];
            }
            

        } else {
        
            $response = [
                'success' => false,
                'data' => 'ERROR_METHOD_NOT_ALLOWED'
            ];
            
            
        }
        
        return new JsonModel($response);
    }
    
    public function capsulesPendingAction()
    {
        $request = $this->getRequest();
        if($request->isGet()) {
            $currentUserPlugin = $this->plugin('currentUserPlugin');
            $currentUser = $currentUserPlugin->getUser();
            
            $name = Functions::sanitizeFilterString($this->params()->fromQuery('name'));
            $order_field = Functions::sanitizeFilterString($this->params()->fromQuery('order_field'));
            $order_direction = Functions::sanitizeFilterString($this->params()->fromQuery('order_direction'));
            
            if(!in_array($order_field,['name', 'added_on'] )) {
                $order_field = 'name';
            }
            
            if(!in_array( $order_direction,['asc', 'desc'])) {
                $order_direction = 'asc'; // Corregido: asignar a $order_direction
            }
            
            $userProgressMapper = MicrolearningUserProgressMapper::getInstance($this->adapter);
            $capsuleMapper = MicrolearningCapsuleMapper::getInstance($this->adapter);
            $topicCapsuleMapper = MicrolearningTopicCapsuleMapper::getInstance($this->adapter); // Añadido
            $topicMapper = MicrolearningTopicMapper::getInstance($this->adapter);
            $capsuleCommentMapper = MicrolearningCapsuleCommentMapper::getInstance($this->adapter); // Reordenado
            
            $accessGranted = $this->getAccessGranted();
             
            // $topics = []; // Ya no es necesario cachear tópicos aquí
            $capsulesData = []; // Renombrado
            
            $storage = Storage::getInstance($this->config, $this->adapter);
            $path = $storage->getPathMicrolearningCapsule();
            
            foreach($accessGranted->capsules as $capsule_id)
            {
                // 1. Verificar progreso (debe ser nulo para pendiente)
                $userProgress = $userProgressMapper->fetchOneByUseridAndCapsuleId($currentUser->id, $capsule_id);
                if($userProgress) {
                    continue;
                }
 
                // 2. Obtener detalles de la cápsula
                $capsule = $capsuleMapper->fetchOne($capsule_id);
                if(!$capsule) { // Añadir verificación por si la cápsula no existe
                    continue;
                }
                
                // 3. Filtrar por nombre
                if($name) {
                    if(empty($name) || stripos($capsule->name, $name) === false) {
                        continue;
                    }
                }
                
                // 4. Obtener Tópico asociado válido
                $topic = null;
                $topic_uuid_for_links = null;
                $relation = $topicCapsuleMapper->fetchOneByCapsuleId($capsule->id);
                if ($relation && in_array($relation->topic_id, $accessGranted->topics)) {
                    $topic = $topicMapper->fetchOne($relation->topic_id);
                    if ($topic) {
                        $topic_uuid_for_links = $topic->uuid;
                    }
                }
 
                // 5. Obtener datos de comentarios
                $dataCountAndRatingAverage = $capsuleCommentMapper->fetchCountAndRatingAverage($capsule->company_id,  $capsule->id);
                
                // 6. Construir enlace slides
                $link_slides = $topic_uuid_for_links ? $this->url()->fromRoute('microlearning/slides', ['topic_id' => $topic_uuid_for_links,  'capsule_id' => $capsule->uuid], ['force_canonical' => true]) : '';
                
                // 7. Añadir al array de resultados
                array_push($capsulesData, [
                    'uuid'              => $capsule->uuid,
                    'name'              => $capsule->name ? $capsule->name : '',
                    'description'       => $capsule->description ? $capsule->description : '',
                    'image'             => $capsule->image ? $storage->getGenericImage($path, $capsule->uuid, $capsule->image)  : '',
                    'position'          => $capsule->order,
                    'link_comments'     => $this->url()->fromRoute('microlearning/capsules-comments', ['capsule_id' => $capsule->uuid], ['force_canonical' => true]),
                    'link_comment_add'  => $this->url()->fromRoute('microlearning/capsules-comments/add', ['capsule_id' => $capsule->uuid],['force_canonical' => true]),
                    'link_slides'       => $link_slides, // Usar enlace construido
                    'total_comments'    => strval($dataCountAndRatingAverage['total_comments']),
                    'total_rating'      => strval($dataCountAndRatingAverage['total_rating']),
                    'progress'          => 0,
                    'added_on'          => $capsule->added_on,
                    'updated_on'        => $capsule->updated_on,
                ]);
            }
            
            // 8. Ordenar
            
            if($order_field == 'name') {
                if($order_direction == 'asc') {
                    usort($capsulesData, function($a, $b) {
                        return strcasecmp($a['name'], $b['name']);
                    });
                } else {
                    usort($capsulesData, function($a, $b) {
                        $result = strcasecmp($a['name'], $b['name']);
                        if($result < 0) { return 1; } else if($result > 0) { return -1; } else { return 0; } // Simplificado
                    });
                }
                
            }
            
            if($order_field == 'added_on') {
                if($order_direction == 'asc') {
                    usort($capsulesData, function($a, $b) {
                        return strcasecmp($a['added_on'], $b['added_on']);
                    });
                } else {
                    usort($capsulesData, function($a, $b) {
                        $result = strcasecmp($a['added_on'], $b['added_on']);
                        if($result < 0) { return 1; } else if($result > 0) { return -1; } else { return 0; } // Simplificado
                    });
                }
                
            }                
                
            // 9. Retornar
            return new JsonModel([
                'success' => true,
                'data' => $capsulesData
            ]);
                
                
                
        }
        
        return new JsonModel([
            'success' => false,
            'data' => 'ERROR_METHOD_NOT_ALLOWED'
        ]);
        
    }
    
    public function capsulesCompletedAction()
    {
        $request = $this->getRequest();
        if($request->isGet()) {
            $currentUserPlugin = $this->plugin('currentUserPlugin');
            $currentUser = $currentUserPlugin->getUser();
            
            $name = Functions::sanitizeFilterString($this->params()->fromQuery('name'));
            $order_field = Functions::sanitizeFilterString($this->params()->fromQuery('order_field'));
            $order_direction = Functions::sanitizeFilterString($this->params()->fromQuery('order_direction'));
            
            if(!in_array($order_field,['name', 'added_on','last_access_on'] )) {
                $order_field = 'name';
            }
            
            if(!in_array( $order_direction,['asc', 'desc'])) {
                $order_field = 'asc';
            }
            
            $userProgressMapper = MicrolearningUserProgressMapper::getInstance($this->adapter);
            $capsuleMapper = MicrolearningCapsuleMapper::getInstance($this->adapter);
            $topicCapsuleMapper = MicrolearningTopicCapsuleMapper::getInstance($this->adapter);
            $topicMapper = MicrolearningTopicMapper::getInstance($this->adapter);
            $capsuleCommentMapper = MicrolearningCapsuleCommentMapper::getInstance($this->adapter);
            
            $accessGranted = $this->getAccessGranted();
            
            $capsulesData = [];
            
            $storage = Storage::getInstance($this->config, $this->adapter);
            $path = $storage->getPathMicrolearningCapsule();
            
            foreach($accessGranted->capsules as $capsule_id)
            {
                // 1. Verificar progreso
                $userProgress = $userProgressMapper->fetchOneByUseridAndCapsuleId($currentUser->id, $capsule_id);
                if(!$userProgress) {
                    continue;
                }
                
                if(!$userProgress->completed) {
                    continue;
                }
                
                // 2. Obtener detalles de la cápsula
                $capsule = $capsuleMapper->fetchOne($capsule_id);
                if(!$capsule) {
                    continue;
                }
                
                // 3. Filtrar por nombre
                if($name) {
                    if(empty($name) || stripos($capsule->name, $name) === false) {
                        continue;
                    }
                }
                
                // 4. Obtener Tópico asociado válido
                $topic = null;
                $topic_uuid_for_links = null;
                $relation = $topicCapsuleMapper->fetchOneByCapsuleId($capsule->id);
                if ($relation && in_array($relation->topic_id, $accessGranted->topics)) {
                    $topic = $topicMapper->fetchOne($relation->topic_id);
                    if ($topic) {
                        $topic_uuid_for_links = $topic->uuid;
                    }
                }

                // 5. Obtener datos de comentarios
                $dataCountAndRatingAverage = $capsuleCommentMapper->fetchCountAndRatingAverage($capsule->company_id, $capsule->id);
                
                // 6. Construir enlace slides
                $link_slides = $topic_uuid_for_links ? $this->url()->fromRoute('microlearning/slides', ['topic_id' => $topic_uuid_for_links,  'capsule_id' => $capsule->uuid], ['force_canonical' => true]) : '';
                
                // 7. Añadir al array de resultados
                array_push($capsulesData, [
                    'uuid'              => $capsule->uuid,
                    'name'              => $capsule->name ? $capsule->name : '',
                    'description'       => $capsule->description ? $capsule->description : '',
                    'image'             => $capsule->image ? $storage->getGenericImage($path, $capsule->uuid, $capsule->image)  : '',
                    'position'          => $capsule->order,
                    'link_comments'     => $this->url()->fromRoute('microlearning/capsules-comments', ['capsule_id' => $capsule->uuid], ['force_canonical' => true]),
                    'link_comment_add'  => $this->url()->fromRoute('microlearning/capsules-comments/add', ['capsule_id' => $capsule->uuid],['force_canonical' => true]),
                    'link_slides'       => $link_slides,
                    'total_comments'    => strval($dataCountAndRatingAverage['total_comments']),
                    'total_rating'      => strval($dataCountAndRatingAverage['total_rating']),
                    'progress'          => $userProgress->progress,
                    'added_on'          => $capsule->added_on,
                    'last_access_on'    => $userProgress->updated_on,
                    'updated_on'        => $capsule->updated_on,
                ]);
            }
            
            // 8. Ordenar (lógica de ordenación permanece igual, usando $capsulesData)
            if($order_field == 'name') {
                if($order_direction == 'asc') {
                    usort($capsulesData, function($a, $b) {
                        return strcasecmp($a['name'], $b['name']);
                    });
                } else {
                    usort($capsulesData, function($a, $b) {
                        $result = strcasecmp($a['name'], $b['name']);
                        if($result < 0) { return 1; } else if($result > 0) { return -1; } else { return 0; }
                    });
                }
            }
            
            if($order_field == 'added_on') {
                if($order_direction == 'asc') {
                    usort($capsulesData, function($a, $b) {
                        return strcasecmp($a['added_on'], $b['added_on']);
                    });
                } else {
                    usort($capsulesData, function($a, $b) {
                        $result = strcasecmp($a['added_on'], $b['added_on']);
                        if($result < 0) { return 1; } else if($result > 0) { return -1; } else { return 0; }
                    });
                }
            }
            
            if($order_field == 'last_access_on') {
                if($order_direction == 'asc') {
                    usort($capsulesData, function($a, $b) {
                        return strcasecmp($a['last_access_on'], $b['last_access_on']);
                    });
                } else {
                    usort($capsulesData, function($a, $b) {
                        $result = strcasecmp($a['last_access_on'], $b['last_access_on']);
                        if($result < 0) { return 1; } else if($result > 0) { return -1; } else { return 0; }
                    });
                }
            }
            
            
            
                
         
            return new JsonModel([
                'success' => true,
                'data' => $capsulesData
            ]);
                
        }
        
        return new JsonModel([
            'success' => false,
            'data' => 'ERROR_METHOD_NOT_ALLOWED'
        ]);
    }
    
    public function capsulesInProgressAction()
    {
        $request = $this->getRequest();
        if($request->isGet()) {
            $currentUserPlugin = $this->plugin('currentUserPlugin');
            $currentUser = $currentUserPlugin->getUser();
            
            $name = Functions::sanitizeFilterString($this->params()->fromQuery('name'));
            $order_field = Functions::sanitizeFilterString($this->params()->fromQuery('order_field'));
            $order_direction = Functions::sanitizeFilterString($this->params()->fromQuery('order_direction'));
            
            if(!in_array($order_field,['name', 'added_on', 'last_access_on'] )) {
                $order_field = 'name';
            }
            
            if(!in_array( $order_direction,['asc', 'desc'])) {
                $order_direction = 'asc';
            }
            
            $userProgressMapper = MicrolearningUserProgressMapper::getInstance($this->adapter);
            $capsuleMapper = MicrolearningCapsuleMapper::getInstance($this->adapter);
            $topicCapsuleMapper = MicrolearningTopicCapsuleMapper::getInstance($this->adapter);
            $topicMapper = MicrolearningTopicMapper::getInstance($this->adapter);
            $capsuleCommentMapper = MicrolearningCapsuleCommentMapper::getInstance($this->adapter);
            
            $accessGranted = $this->getAccessGranted();
            
            $capsulesData = [];
            
            $storage = Storage::getInstance($this->config, $this->adapter);
            $path = $storage->getPathMicrolearningCapsule();
            
            foreach($accessGranted->capsules as $capsule_id)
            {
                // 1. Verificar progreso
                $userProgress = $userProgressMapper->fetchOneByUseridAndCapsuleId($currentUser->id, $capsule_id);
                if(!$userProgress || $userProgress->completed) { // Si no hay progreso o ya está completada
                    continue;
                }

                // 2. Obtener detalles de la cápsula
                $capsule = $capsuleMapper->fetchOne($capsule_id);
                if(!$capsule) {
                    continue;
                }
                
                // 3. Filtrar por nombre
                if($name) {
                    if(empty($name) || stripos($capsule->name, $name) === false) {
                        continue;
                    }
                }
                
                // 4. Obtener Tópico asociado válido
                $topic = null;
                $topic_uuid_for_links = null;
                $relation = $topicCapsuleMapper->fetchOneByCapsuleId($capsule->id);
                if ($relation && in_array($relation->topic_id, $accessGranted->topics)) {
                    $topic = $topicMapper->fetchOne($relation->topic_id);
                    if ($topic) {
                        $topic_uuid_for_links = $topic->uuid;
                    }
                }

                // 5. Obtener datos de comentarios
                $dataCountAndRatingAverage = $capsuleCommentMapper->fetchCountAndRatingAverage($capsule->company_id,  $capsule->id);
                
                // 6. Construir enlace slides
                $link_slides = $topic_uuid_for_links ? $this->url()->fromRoute('microlearning/slides', ['topic_id' => $topic_uuid_for_links,  'capsule_id' => $capsule->uuid], ['force_canonical' => true]) : '';
                
                // 7. Añadir al array de resultados
                array_push($capsulesData, [
                    'uuid'              => $capsule->uuid,
                    'name'              => $capsule->name ? $capsule->name : '',
                    'description'       => $capsule->description ? $capsule->description : '',
                    'image'             => $capsule->image ? $storage->getGenericImage($path, $capsule->uuid, $capsule->image)  : '',
                    'position'          => $capsule->order,
                    'link_comments'     => $this->url()->fromRoute('microlearning/capsules-comments', ['capsule_id' => $capsule->uuid], ['force_canonical' => true]),
                    'link_comment_add'  => $this->url()->fromRoute('microlearning/capsules-comments/add', ['capsule_id' => $capsule->uuid],['force_canonical' => true]),
                    'link_slides'       => $link_slides,
                    'total_comments'    => strval($dataCountAndRatingAverage['total_comments']),
                    'total_rating'      => strval($dataCountAndRatingAverage['total_rating']),
                    'progress'          => $userProgress->progress,
                    'last_access_on'    => $userProgress->updated_on,
                    'added_on'          => $capsule->added_on,
                    'updated_on'        => $capsule->updated_on,
                ]);
            }
            
            // 8. Ordenar (lógica de ordenación permanece igual, usando $capsulesData)
            if($order_field == 'name') {
                if($order_direction == 'asc') {
                    usort($capsulesData, function($a, $b) {
                        return strcasecmp($a['name'], $b['name']);
                    });
                } else {
                    usort($capsulesData, function($a, $b) {
                        $result = strcasecmp($a['name'], $b['name']);
                        if($result < 0) { return 1; } else if($result > 0) { return -1; } else { return 0; }
                    });
                }
            }
            
            if($order_field == 'added_on') {
                if($order_direction == 'asc') {
                    usort($capsulesData, function($a, $b) {
                        return strcasecmp($a['added_on'], $b['added_on']);
                    });
                } else {
                    usort($capsulesData, function($a, $b) {
                        $result = strcasecmp($a['added_on'], $b['added_on']);
                        if($result < 0) { return 1; } else if($result > 0) { return -1; } else { return 0; }
                    });
                }
            }
            
            if($order_field == 'last_access_on') {
                if($order_direction == 'asc') {
                    usort($capsulesData, function($a, $b) {
                        return strcasecmp($a['last_access_on'], $b['last_access_on']);
                    });
                } else {
                    usort($capsulesData, function($a, $b) {
                        $result = strcasecmp($a['last_access_on'], $b['last_access_on']);
                        if($result < 0) { return 1; } else if($result > 0) { return -1; } else { return 0; }
                    });
                }
            }
                
                
            return new JsonModel([
                'success' => true,
                'data' => $capsulesData
            ]);
        }
        
        return new JsonModel([
            'success' => false,
            'data' => 'ERROR_METHOD_NOT_ALLOWED'
        ]);
    }
    
    
    public function timelineAction()
    {
        
        $request = $this->getRequest();
        if($request->isGet()) {
            $currentUserPlugin = $this->plugin('currentUserPlugin');
            $currentUser = $currentUserPlugin->getUser();
            
            
            $page = intval($this->params()->fromQuery('page'), 10);
            
            $activities = [
                MicrolearningUserLog::ACTIVITY_SIGNIN            => 'LABEL_MICROLEARNING_ACTIVITY_SIGNIN',
                MicrolearningUserLog::ACTIVITY_SIGNOUT           => 'LABEL_MICROLEARNING_ACTIVITY_SIGNOUT',
                MicrolearningUserLog::ACTIVITY_START_TOPIC       => 'LABEL_MICROLEARNING_ACTIVITY_START_TOPIC',
                MicrolearningUserLog::ACTIVITY_START_CAPSULE     => 'LABEL_MICROLEARNING_ACTIVITY_START_CAPSULE',
                MicrolearningUserLog::ACTIVITY_VIEW_SLIDE        => 'LABEL_MICROLEARNING_ACTIVITY_VIEW_SLIDE',
                MicrolearningUserLog::ACTIVITY_TAKE_A_TEST       => 'LABEL_MICROLEARNING_ACTIVITY_TAKE_A_TEST',
                MicrolearningUserLog::ACTIVITY_RETAKE_A_TEST     => 'LABEL_MICROLEARNING_ACTIVITY_RETAKE_A_TEST',
                MicrolearningUserLog::ACTIVITY_APPROVED_TEST     => 'LABEL_MICROLEARNING_ACTIVITY_APPROVED_TEST',
                MicrolearningUserLog::ACTIVITY_COMPLETED_CAPSULE => 'LABEL_MICROLEARNING_ACTIVITY_COMPLETED_CAPSULE',
                MicrolearningUserLog::ACTIVITY_COMPLETED_TOPIC   => 'LABEL_MICROLEARNING_ACTIVITY_COMPLETED_TOPIC',
            ];
            

            
            $microlearningUserLogMapper = MicrolearningUserLogMapper::getInstance($this->adapter);
            $paginator = $microlearningUserLogMapper->getAllMessagesPaginatorByUserId($currentUser->id, $page);
            
            $items = [];
            foreach($paginator as $record)
            {
                $dt = \DateTime::createFromFormat('Y-m-d H:i:s', $record->added_on);
                
                array_push($items, [
                    'activity' => $activities[$record->activity],
                    'added_on' => $dt->format('d/m/Y H:i a')
                ]);
            }
            
            
            return new JsonModel([
                'success' => true,
                'data' => [
                    'total' => [
                        'count' => $paginator->getTotalItemCount(),
                        'pages' => $paginator->getPages()->pageCount,
                    ],
                    'current' => [
                        'items'    => $items,
                        'page'     => $paginator->getCurrentPageNumber(),
                        'count'    => $paginator->getCurrentItemCount(),
                    ]
                ]
            ]);
            
            
        } else {
            return new JsonModel([
                'success' => false,
                'data' => 'ERROR_METHOD_NOT_ALLOWED'
            ]);
        }
    }
    
    /**
     * Valores para la generación de los gráficos de progreso
     * Para las repuesta afirmativa
     * [
     *  'success' => true,
     *      'data' => [
     *          'topicTotal' => cantidad total de tópicos,
     *          'topicStarted' => cantidad de tópicos iniciados,
     *          'topicIncompleted' => cantidad de tópicos incompletos,
     *          'topicCompleted' => cantidad de tópicos completos,
     *          'percentCompleted' => % de diapositivas completados ,
     *          'percentIncompleted' => % de diapositivas incompletos ,
     *          'percentWithoutReturning' => % de cápsulas sin retorno después de completada,
     *          'percentWithReturning' => % de cápsulas con retorno después de completada,
     *      ],
     * ]
     *
     *
     *  En caso contrario
     *  [
     *      'success' => false,
     *      'data' => mensaje de error
     *  ]
     *
     *
     * @return \Laminas\View\Model\JsonModel
     */
    public function progressAction()
    {
        
        $request = $this->getRequest();
        if($request->isGet()) {
            $currentUserPlugin = $this->plugin('currentUserPlugin');
            $currentUser = $currentUserPlugin->getUser();
            
            
            $accessGrantedIds = $this->getAccessGranted();
            $id = $this->params()->fromRoute('id');
            
            $companyMapper = CompanyMapper::getInstance($this->adapter);
            $company = $companyMapper->fetchOneByUuid($id);
            
            if(!$company) {
                $response = [
                    'success' => false,
                    'data' => 'ERROR_COMPANY_NOT_FOUND',
                ];
                
                
                return new JsonModel($response);
            }
            
            if(!in_array($company->id, $accessGrantedIds->companies)) {
                $response = [
                    'success' => false, 
                    'data' => 'ERROR_YOU_DO_NOT_HAVE_ACCESS_TO_THIS_COMPANY',
                ]; 
                
                
                return new JsonModel($response);
            }
            
            $capsuleTotal              = 0;
            $capsuleCompleted          = 0;
            $capsuleWithReturning      = 0;
            $capsuleWithoutReturning   = 0;
            $capsuleStarted            = 0;
            $capsuleToStart            = 0;
            $percentCompleted          = 0;
            $percentIncompleted        = 100;
            
            $topicMapper = MicrolearningTopicMapper::getInstance($this->adapter);
            $topics = $topicMapper->fetchAllActiveByCompanyIdAndIds($company->id, $accessGrantedIds->topics);
            
            //$capsuleMapper = MicrolearningCapsuleMapper::getInstance($this->adapter);
            $progressMapper = MicrolearningUserProgressMapper::getInstance($this->adapter);
            
            $topicCapsuleMapper = MicrolearningTopicCapsuleMapper::getInstance($this->adapter);
            
            //$capsuleUserMapper = MicrolearningCapsuleUserMapper::getInstance($this->adapter);
            
            
            foreach($topics as $topic)
            {
                $resultCount = $topicCapsuleMapper->fetchCountByCompanyIdAndTopicId($company->id, $topic->id);
                $capsuleTotal =  $capsuleTotal + $resultCount;
                
                $resultCount = $progressMapper->fetchCountCapsulesCompletedByIdAndTopicId($currentUser->id, $topic->id);
                $capsuleCompleted = $capsuleCompleted + $resultCount;
                
                $resultCount = $progressMapper->fetchCountCapsulesCompletedWithReturningByIdAndTopicId($currentUser->id, $topic->id);
                $capsuleWithReturning = $capsuleWithReturning + $resultCount;
                
                $resultCount = $progressMapper->fetchCountCapsulesCompletedWithoutReturningByIdAndTopicId($currentUser->id, $topic->id);
                $capsuleWithoutReturning = $capsuleWithoutReturning + $resultCount;
                
                $resultCount = $progressMapper->fetchCountCapsulesCompletedByIdAndTopicId($currentUser->id, $topic->id);
                $capsuleStarted = $capsuleStarted + $resultCount;
            }
   
            $capsuleToStart = $capsuleTotal -  $capsuleStarted;
            
            
            if($capsuleTotal > 0) {
                $percentCompleted = ($capsuleCompleted * 100) /  $capsuleTotal;
                $percentIncompleted = 100 - $percentCompleted;
            }
            
            
            
            return new JsonModel([
                'success' => true,
                'data' => [
                    'capsuleTotal' => $capsuleTotal,
                    'capsuleCompleted' => $capsuleCompleted,
                    'capsuleStarted' => $capsuleStarted,
                    'capsuleToStart' => $capsuleToStart,
                    'percentCompleted' => number_format($percentCompleted, 2, '.', ','),
                    'percentIncompleted' => number_format($percentIncompleted, 2, '.', ','),
                    'capsuleWithReturning' => $capsuleWithReturning,
                    'capsuleWithoutReturning' => $capsuleWithoutReturning,
                ],
            ]);
            
            
        } else {
            return new JsonModel([
                'success' => false,
                'data' => 'ERROR_METHOD_NOT_ALLOWED'
            ]);
        }
    }
    
    
    public function topicsAction()
    {
        $request = $this->getRequest();
        if($request->isGet()) {
            $currentUserPlugin = $this->plugin('currentUserPlugin');
            $currentUser = $currentUserPlugin->getUser();
            
            
            $data = [];
            $accessGrantedIds = $this->getAccessGranted();
            
            $userProgressMapper = MicrolearningUserProgressMapper::getInstance($this->adapter);
            $topicMapper = MicrolearningTopicMapper::getInstance($this->adapter);
            
            $storage = Storage::getInstance($this->config, $this->adapter);
            $path = $storage->getPathMicrolearningTopic();
            
            foreach($accessGrantedIds->topics as $id)
            {
                $topic = $topicMapper->fetchOne($id);
                if(!$topic) {
                    continue;
                }
                
                $userProgress = $userProgressMapper->fetchOneByUserIdAndTopicId($currentUser->id, $id);
                if($userProgress) {
                    $progress = $userProgress->progress;
                    $completed = $userProgress->completed;
                } else {
                    $progress = 0;
                    $completed = 0;
                }
                
                
            
                array_push($data, [
                    'uuid'          => $topic->uuid,
                    'name'          => $topic->name ? $topic->name : '',
                    'description'   => $topic->description ? $topic->description : '',
                    'image'         => $topic->image ? $storage->getGenericImage($path, $topic->uuid, $topic->image) : '',
                    'progress'      => $progress,
                    'completed'     => $completed,
                    'order'         => $topic->order,
                    'added_on'      => $topic->added_on,
                    'updated_on'    => $topic->updated_on
                ]);
            }
            
            usort($data, function($a, $b) {
        
                $result =  $a['order'] <=> $b['order'];
                if(0 == $result) {
                    $result = strcasecmp($a['added_on'], $b['added_on']);
                    if(0 == $result) {
                        $result = strcasecmp($a['name'], $b['name']);
                    }
                }
        
                if($result < 0) {
                    return 1;
                } else if($result > 0) {
                    return -1;
                } else  {
                    return  0;
                }
            });
            
            
            
                return new JsonModel([
                    'success' => true,
                    'data' => $data
                ]);
            
        } else {
            return new JsonModel([
                'success' => false,
                'data' => 'ERROR_METHOD_NOT_ALLOWED'
            ]);
        }
    }
    
    public function getTopicAction()
    {
        // Handle GET request
        $request = $this->getRequest();
        if($request->isGet()) {
            // Get current user
            $currentUserPlugin = $this->plugin('currentUserPlugin');
            $currentUser = $currentUserPlugin->getUser();

            // Get topic ID from route
            $id = $this->params()->fromRoute('id');
            $topicMapper = MicrolearningTopicMapper::getInstance($this->adapter);
            $topic = $topicMapper->fetchOneByUuid($id);

            // Return error if topic not found
            if(!$topic) {
                return new JsonModel([
                    'success' => false,
                    'data' => 'ERROR_TOPIC_NOT_FOUND'
                ]);
            }

            // Check if current user has access to the topic
            $accessGrantedIds = $this->getAccessGranted();
            if(!in_array($topic->id, $accessGrantedIds->topics)) {
                return new JsonModel([
                    'success' => false,
                    'data' => 'ERROR_YOU_DO_NOT_HAVE_ACCESS_TO_THIS_TOPIC'
                ]);
            }

            // Get user progress for this topic
            $userProgressMapper = MicrolearningUserProgressMapper::getInstance($this->adapter);
            $userProgress = $userProgressMapper->fetchOneByUserIdAndTopicId($currentUser->id, $topic->id);

            $progress = $userProgress->progress ?? 0;
            $completed = $userProgress->completed ?? 0;

            // Initialize storage service to get image paths
            $storage = Storage::getInstance($this->config, $this->adapter);
            $pathTopic = $storage->getPathMicrolearningTopic();

            // Fetch associated capsules using the private helper method
            $capsulesData = $this->_getCapsulesByTopic($topic, $storage);

            // Prepare data for JSON response
            $data = [
                'uuid'          => $topic->uuid,
                'name'          => $topic->name ? $topic->name : '',
                'description'   => $topic->description ? $topic->description : '',
                'image'         => $topic->image ? $storage->getGenericImage($pathTopic, $topic->uuid, $topic->image) : '',
                'progress'      => $progress,
                'completed'     => $completed,
                'order'         => $topic->order,
                'added_on'      => $topic->added_on,
                'updated_on'    => $topic->updated_on,
                'total_capsules' => count($capsulesData),
                'capsules'      => $capsulesData,
            ];

            return new JsonModel([
                'success' => true,
                'data' => $data
            ]);

        } else {
            // Return error if not a GET request
            return new JsonModel([
                'success' => false,
                'data' => 'ERROR_METHOD_NOT_ALLOWED'
            ]);
        }
    }

    /**
     * @param MicrolearningTopic $topic The topic object.
     * @param Storage $storage The storage object.
     * @return array The capsules data.
     */
    private function _getCapsulesByTopic($topic, $storage)
    {
        $data = [];
        $accessGrantedIds = $this->getAccessGranted();

        if (!$topic) {
            return $data;
        }

        if (!in_array($topic->id, $accessGrantedIds->topics)) {
            return $data;
        }

        $currentUserPlugin = $this->plugin('currentUserPlugin');
        $currentUser = $currentUserPlugin->getUser();

        $topicCapsuleMapper = MicrolearningTopicCapsuleMapper::getInstance($this->adapter);
        $topicCapsuleRelations = $topicCapsuleMapper->fetchAllActiveByTopicId($topic->id);

        $userProgressMapper = MicrolearningUserProgressMapper::getInstance($this->adapter);
        $capsuleCommentMapper = MicrolearningCapsuleCommentMapper::getInstance($this->adapter);

        $path = $storage->getPathMicrolearningCapsule();

        foreach ($topicCapsuleRelations as $relation) {
            if(!in_array($relation->capsule_id, $accessGrantedIds->capsules)) {
                continue;
            }

            $capsuleMapper = MicrolearningCapsuleMapper::getInstance($this->adapter);
            $capsule = $capsuleMapper->fetchOne($relation->capsule_id);

            if(!$capsule) {
                continue;
            }

            $userProgress = $userProgressMapper->fetchOneByUseridAndCapsuleId($currentUser->id, $capsule->id);
            $progress = $userProgress->progress ?? 0;
            $completed = $userProgress->completed ?? 0;
            $dataCountAndRatingAverage = $capsuleCommentMapper->fetchCountAndRatingAverage($capsule->company_id, $capsule->id);
            $image = $capsule->image ? $storage->getGenericImage($path, $capsule->uuid, $capsule->image) : '';
            $total_comments = strval($dataCountAndRatingAverage['total_comments']);
            $total_rating = strval($dataCountAndRatingAverage['total_rating']);

            array_push($data, [
                'uuid'              => $capsule->uuid,
                'name'              => $capsule->name ? $capsule->name : '',
                'description'       => $capsule->description ? $capsule->description : '',
                'image'             => $image,
                'total_comments'    => $total_comments,
                'total_rating'      => $total_rating,
                'progress'          => $progress,
                'completed'         => $completed,
                'order'             => $capsule->order,
                'added_on'          => $capsule->added_on,
                'updated_on'        => $capsule->updated_on,
            ]);
        }

        return $data;
    }

    /**
     * @param MicrolearningCapsule $capsule The capsule object.
     * @param Storage $storage The storage object.
     * @return array The slides data.
     */
    private function _getSlidesByCapsule($capsule, $storage)
    {
        $data = [];
        $accessGrantedIds = $this->getAccessGranted();

        if (!$capsule) {
            return $data;
        }

        if (!in_array($capsule->id, $accessGrantedIds->capsules)) {
            return $data;
        }

        $currentUserPlugin = $this->plugin('currentUserPlugin');
        $currentUser = $currentUserPlugin->getUser();

        $slideMapper = MicrolearningSlideMapper::getInstance($this->adapter);
        $userProgressMapper = MicrolearningUserProgressMapper::getInstance($this->adapter);
        $quizMapper = MicrolearningQuizMapper::getInstance($this->adapter);

        $path = $storage->getPathMicrolearningSlide();
        $slides = $slideMapper->fetchAllByCompanyIdAndCapsuleId($capsule->company_id, $capsule->id);

        foreach ($slides as $slide) {
            $userProgress = $userProgressMapper->fetchOneByUserIdAndSlideId($currentUser->id, $slide->id);
            $completed = $userProgress ? $userProgress->completed : 0;

            $quiz_uuid = '';
            $quiz_data = [];
            $link_take_a_test = '';

            if ($slide->quiz_id) {
                $quiz = $quizMapper->fetchOne($slide->quiz_id);
                if ($quiz) {
                    $quiz_uuid = $quiz->uuid;
                    $quiz_data = $this->getQuiz($slide->quiz_id);
                    $link_take_a_test = $this->url()->fromRoute('microlearning/take-a-test', ['slide_id' => $slide->uuid], ['force_canonical' => true]);
                }
            }

            array_push($data, [
                'quiz'                  => $quiz_uuid,
                'quiz_data'             => $quiz_data,
                'uuid'                  => $slide->uuid,
                'name'                  => $slide->name ? $slide->name : '',
                'description'           => $slide->description ? $slide->description : '',
                'type'                  => $slide->type,
                'background'            => $slide->background ? $storage->getGenericImage($path, $slide->uuid, $slide->background) : '',
                'file'                  => $slide->file ? $storage->getGenericFile($path, $slide->uuid, $slide->file) : '',
                'order'                 => $slide->order,
                'completed'             => $completed,
                'link_take_a_test'      => $link_take_a_test,
                'added_on'              => $slide->added_on,
                'updated_on'            => $slide->updated_on,
            ]);
        }

        // Sort slides by order, then by added_on, then by name
        usort($data, function($a, $b) {
            $result = $a['order'] <=> $b['order'];
            if (0 == $result) {
                $result = strcasecmp($a['added_on'], $b['added_on']);
                if (0 == $result) {
                    $result = strcasecmp($a['name'], $b['name']);
                }
            }

            if ($result < 0) {
                return 1;
            } else if ($result > 0) {
                return -1;
            } else {
                return 0;
            }
        });

        return $data;
    }

    public function capsulesAction()
    {
        $request = $this->getRequest();
        if($request->isGet()) {
            $currentUserPlugin = $this->plugin('currentUserPlugin');
            $currentUser = $currentUserPlugin->getUser();

            $topic_id_param = $this->params()->fromRoute('topic_id');
            $topicMapper = MicrolearningTopicMapper::getInstance($this->adapter);
            $topic = $topicMapper->fetchOneByUuid($topic_id_param);

            if(!$topic) {
                return new JsonModel([
                    'success' => false,
                    'data' => 'ERROR_TOPIC_NOT_FOUND'
                ]);
            }

            $accessGrantedIds = $this->getAccessGranted();

            if(!in_array($topic->id, $accessGrantedIds->topics)) {
                return new JsonModel([
                    'success' => false,
                    'data' => 'ERROR_YOU_DO_NOT_HAVE_ACCESS_TO_THIS_TOPIC'
                ]);
            }

            $storage = Storage::getInstance($this->config, $this->adapter);
            // Use the _getCapsulesByTopic method to fetch capsules
            $data = $this->_getCapsulesByTopic($topic, $storage);

            // The _getCapsulesByTopic method already returns capsules with the required data structure.
            // We just need to sort them.

            usort($data, function($a, $b) {

                $result =  $a['order'] <=> $b['order'];
                if(0 == $result) {
                    $result = strcasecmp($a['added_on'], $b['added_on']);
                    if(0 == $result) {
                        $result = strcasecmp($a['name'], $b['name']);
                    }
                }

                if($result < 0) {
                    return 1;
                } else if($result > 0) {
                    return -1;
                } else  {
                    return  0;
                }
            });

            return new JsonModel([
                'success' => true,
                'data' => $data
            ]);

        } else {
            return new JsonModel([
                'success' => false,
                'data' => 'ERROR_METHOD_NOT_ALLOWED'
            ]);
        }
    }
    
    public function takeTestAction() 
    {
        $request = $this->getRequest();
        if($request->isPost()) {
            $currentUserPlugin = $this->plugin('currentUserPlugin');
            $currentUser = $currentUserPlugin->getUser();
            
            $slide_id = $this->params()->fromRoute('slide_id');
            $slideMapper = MicrolearningSlideMapper::getInstance($this->adapter);
            $slide = $slideMapper->fetchOneByUuid($slide_id);
            
            if(!$slide) {
                return new JsonModel([
                    'success' => false,
                    'data' => 'ERROR_SLIDE_NOT_FOUND'
                ]);
            }
            
            if($slide->type != MicrolearningSlide::TYPE_QUIZ) {
                return new JsonModel([
                    'success' => false,
                    'data' => 'ERROR_SLIDE_IS_NOT_QUIZ'
                ]);
            }
            
            
        
            $capsuleMapper = MicrolearningCapsuleMapper::getInstance($this->adapter);
            $capsule = $capsuleMapper->fetchOne($slide->capsule_id);
            
            if(!$capsule) {
                return new JsonModel([
                    'success' => false,
                    'data' => 'ERROR_CAPSULE_NOT_FOUND'
                ]);
            }
            
            $accessGrantedIds = $this->getAccessGranted();
            
            if(!in_array($capsule->id, $accessGrantedIds->capsules)) {
                return new JsonModel([
                    'success' => false,
                    'data' => 'ERROR_YOU_DO_NOT_HAVE_ACCESS_TO_THIS_CAPSULE'
                ]);
            }
            
            $userLogMapper = MicrolearningUserLogMapper::getInstance($this->adapter);
            $userLog = $userLogMapper->fetchOneTakeATestByUserIdAndSlideId($currentUser->id, $slide->id);
            
            if($userLog) {
                $activity = MicrolearningUserLog::ACTIVITY_RETAKE_A_TEST;
            } else {
                $activity = MicrolearningUserLog::ACTIVITY_TAKE_A_TEST;
            }
            
            $added_on = $userLogMapper->getDatebaseNow();
            
            $userLog = new MicrolearningUserLog();
            $userLog->activity      = $activity;
            $userLog->user_id       = $currentUser->id;
            $userLog->company_id    = $slide->company_id;
            $userLog->topic_id      = $slide->topic_id;
            $userLog->capsule_id    = $slide->capsule_id;
            $userLog->slide_id      = $slide->id;
            $userLog->added_on      = $added_on;
            
            if($userLogMapper->insert($userLog)) {
                return new JsonModel([
                    'success' => true,
                ]);
            } else {
                return new JsonModel([
                    'success' => false,
                    'data' => $userLogMapper->getError()
                ]);
            }
            
            
            
            
            
            
            
        } else {
            return new JsonModel([
                'success' => false,
                'data' => 'ERROR_METHOD_NOT_ALLOWED'
            ]);
        }
    }
    
    public function getCapsuleAction()
    {
        $request = $this->getRequest();

        if($request->isGet()) {
            $currentUserPlugin = $this->plugin('currentUserPlugin');
            $currentUser = $currentUserPlugin->getUser();
            
            $capsule_uuid = $this->params()->fromRoute('id');
            $capsuleMapper = MicrolearningCapsuleMapper::getInstance($this->adapter);
            $capsule = $capsuleMapper->fetchOneByUuid($capsule_uuid);
            
            if(!$capsule) {
                return new JsonModel([
                    'success' => false,
                    'data' => 'ERROR_CAPSULE_NOT_FOUND'
                ]);
            }
            
            $accessGrantedIds = $this->getAccessGranted();
            
            if(!in_array($capsule->id, $accessGrantedIds->capsules)) {
                return new JsonModel([
                    'success' => false,
                    'data' => 'ERROR_YOU_DO_NOT_HAVE_ACCESS_TO_THIS_CAPSULE'
                ]);
            }
            
            $userProgressMapper = MicrolearningUserProgressMapper::getInstance($this->adapter);
            $capsuleCommentMapper = MicrolearningCapsuleCommentMapper::getInstance($this->adapter);
            
            $userProgress = $userProgressMapper->fetchOneByUseridAndCapsuleId($currentUser->id, $capsule->id);
            $progress = $userProgress->progress ?? 0;
            $completed = $userProgress->completed ?? 0;
            
            $dataCountAndRatingAverage = $capsuleCommentMapper->fetchCountAndRatingAverage($capsule->company_id, $capsule->id);
            
            // Get comments data
            $userMapper = UserMapper::getInstance($this->adapter);
            $storage = Storage::getInstance($this->config, $this->adapter);
            $serviceDatetimeFormat = $this->config['leaderslinked.services.datetime'];
            
            $comments = [];
            $records = $capsuleCommentMapper->fetchAllByCapsuleId($capsule->id);
            foreach($records as $record) {
                $user = $userMapper->fetchOne($record->user_id);
                if(!$user) {
                    continue;
                }
                
                $dt = \DateTime::createFromFormat('Y-m-d H:i:s', $record->added_on);
                
                array_push($comments, [
                    'uuid' => $record->uuid,
                    'date' => $dt->format($serviceDatetimeFormat),
                    'image' => $storage->getUserImage($user),
                    'fullname' => trim(trim($user->first_name) . ' ' . trim($user->last_name)),
                    'rating' => strval($record->rating),
                    'comment' => $record->comment,
                    'link_delete' => $record->user_id == $currentUser->id ? $this->url()->fromRoute('microlearning/capsules-comments/delete', ['capsule_id' => $capsule->uuid, 'comment_id' => $record->uuid], ['force_canonical' => true]) : ''
                ]);
            }
            
            $storage = Storage::getInstance($this->config, $this->adapter);
            $path = $storage->getPathMicrolearningCapsule();
            
            $slides = $this->_getSlidesByCapsule($capsule, $storage);
            
            $data = [
                'uuid'              => $capsule->uuid,
                'name'              => $capsule->name ? $capsule->name : '',
                'description'       => $capsule->description ? $capsule->description : '',
                'image'             => $capsule->image ? $storage->getGenericImage($path, $capsule->uuid, $capsule->image) : '',
                'link_comment_add'  => $this->url()->fromRoute('microlearning/capsules-comments/add', ['capsule_id' => $capsule->uuid], ['force_canonical' => true]),
                'total_comments'    => strval($dataCountAndRatingAverage['total_comments']),
                'total_rating'      => strval($dataCountAndRatingAverage['total_rating']),
                'comments'          => $comments,
                'progress'          => $progress,
                'completed'         => $completed,
                'total_slides'      => count($slides),
                'slides'            => $slides,
                'order'             => $capsule->order,
                'added_on'          => $capsule->added_on,
                'updated_on'        => $capsule->updated_on,
            ];
            
            return new JsonModel([
                'success' => true,
                'data' => $data
            ]);
        }
        
        return new JsonModel([
            'success' => false,
            'data' => 'ERROR_METHOD_NOT_ALLOWED'
        ]);
    }
    
    public function slidesAction()
    {
        $request = $this->getRequest();
        if($request->isGet()) {
            $currentUserPlugin = $this->plugin('currentUserPlugin');
            $currentUser = $currentUserPlugin->getUser();
            
            
            
            $topic_id = $this->params()->fromRoute('topic_id');
            $topicMapper = MicrolearningTopicMapper::getInstance($this->adapter);
            $topic = $topicMapper->fetchOneByUuid($topic_id);
            
            if(!$topic) {
                return new JsonModel([
                    'success' => false,
                    'data' => 'ERROR_TOPIC_NOT_FOUND'
                ]);
            }
            
            $accessGrantedIds = $this->getAccessGranted();
            
            if(!in_array($topic->id, $accessGrantedIds->topics)) {
                return new JsonModel([
                    'success' => false,
                    'data' => 'ERROR_YOU_DO_NOT_HAVE_ACCESS_TO_THIS_TOPIC'
                ]);
            }
            
            $capsule_id = $this->params()->fromRoute('capsule_id');
            $capsuleMapper = MicrolearningCapsuleMapper::getInstance($this->adapter);
            $capsule = $capsuleMapper->fetchOneByUuid($capsule_id);
            
            if(!$capsule) {
                return new JsonModel([
                    'success' => false,
                    'data' => 'ERROR_CAPSULE_NOT_FOUND'
                ]);
            }
            
          
            
            if(!in_array($capsule->id, $accessGrantedIds->capsules)) {
                return new JsonModel([
                    'success' => false,
                    'data' => 'ERROR_YOU_DO_NOT_HAVE_ACCESS_TO_THIS_CAPSULE'
                ]);
            }
            

            
            $data = [];
            
            $quizMapper = MicrolearningQuizMapper::getInstance($this->adapter);
            
            $slideMapper = MicrolearningSlideMapper::getInstance($this->adapter);
            $userProgressMapper = MicrolearningUserProgressMapper::getInstance($this->adapter);
            
            $storage = Storage::getInstance($this->config, $this->adapter);
            $path = $storage->getPathMicrolearningSlide();
            
            $slides = $slideMapper->fetchAllByCompanyIdAndTopicIdAndCapsuleId($capsule->company_id, $capsule->topic_id, $capsule->id);
            foreach($slides as $slide)
            {
       
                
                $userProgress = $userProgressMapper->fetchOneByUserIdAndSlideId($currentUser->id, $slide->id);
                if($userProgress) {
                    $completed =  $userProgress->completed ;
                } else {
                    $completed = 0;
                }
                

                
                $link_take_a_test = '';
                if($slide->quiz_id) {
                    
                    $quizMapper = MicrolearningQuizMapper::getInstance($this->adapter);
                    $quiz = $quizMapper->fetchOne($slide->quiz_id);
                    if($quiz) {
                        $quiz_uuid = $quiz->uuid;
                        $quiz_data = $this->getQuiz($slide->quiz_id);
                        $link_take_a_test = $this->url()->fromRoute('microlearning/take-a-test', ['slide_id' => $slide->uuid], ['force_canonical' => true]);
                    }
                    
                } 

                
                array_push($data, [
                    'quiz'                  => $quiz_uuid,
                    'quiz_data'             => $quiz_data,
                    'uuid'                  => $slide->uuid,
                    'name'                  => $slide->name ? $slide->name : '',
                    'description'           => $slide->description ? $slide->description : '',
                    'type'                  => $slide->type,
                    'background'            => $slide->background ? $storage->getGenericImage($path, $slide->uuid, $slide->background) : '',
                    'file'                  => $slide->file ? $storage->getGenericFile($path, $slide->uuid, $slide->file) : '',
                    'order'                 => $slide->order,
                    'completed'             => $completed,
                    'link_take_a_test'      => $link_take_a_test,
                    'added_on'              => $slide->added_on,
                    'updated_on'            => $slide->updated_on,
                ]);
                
                
                
            }
            
            usort($data, function($a, $b) {
                
                $result =  $a['order'] <=> $b['order'];
                if(0 == $result) {
                    $result = strcasecmp($a['added_on'], $b['added_on']);
                    if(0 == $result) {
                        $result = strcasecmp($a['name'], $b['name']);
                    }
                }
                
                if($result < 0) {
                    return 1;
                } else if($result > 0) {
                    return -1;
                } else  {
                    return  0;
                }
            });
                
                
                
                return new JsonModel([
                    'success' => true,
                    'data' => $data
                ]);
                
        } else {
            return new JsonModel([
                'success' => false,
                'data' => 'ERROR_METHOD_NOT_ALLOWED'
            ]);
        }
    }
    
    private function getQuiz($id) 
    {
        $serviceDatetimeFormat = $this->config['leaderslinked.services.datetime'];
        
        $data = [];
        
        $quizMapper = MicrolearningQuizMapper::getInstance($this->adapter);
        $quiz = $quizMapper->fetchOne($id);
        
        if(!$quiz) {
            return [];
        }
        
        $companyMapper = CompanyMapper::getInstance($this->adapter);
        $company = $companyMapper->fetchOne($quiz->company_id);
        
        $questionMapper = MicrolearningQuestionMapper::getInstance($this->adapter);
        $answerMapper = MicrolearningAnswerMapper::getInstance($this->adapter);
        
        $record_questions = [];
        $questions = $questionMapper->fetchAllByQuizId($quiz->id);
        foreach($questions as $question)
        {
            $record_answers = [];
                
            $answers = $answerMapper->fetchAllByQuizIdAndQuestionId($question->quiz_id, $question->id);
            foreach($answers as $answer)
            {
                $dtAddedOn = \DateTime::createFromFormat('Y-m-d H:i:s', $answer->added_on);
                $dtUpdatedOn = \DateTime::createFromFormat('Y-m-d H:i:s', $answer->updated_on);
                    
                array_push($record_answers, [
                    'uuid' => $answer->uuid,
                    'text' => trim($answer->text),
                    'correct' => $answer->correct ? $answer->correct  : 0 ,
                    'points' => strval(intval($answer->points, 10)),
                    'added_on'  => $dtAddedOn->format($serviceDatetimeFormat),
                    'updated_on'    => $dtUpdatedOn->format($serviceDatetimeFormat),
                ]);
            }
                
            $dtAddedOn = \DateTime::createFromFormat('Y-m-d H:i:s', $question->added_on);
            $dtUpdatedOn = \DateTime::createFromFormat('Y-m-d H:i:s', $question->updated_on);
                
            array_push($record_questions, [
                'uuid'          => $question->uuid,
                'text'          => trim($question->text),
                'type'          => $question->type,
                'maxlength'     => strval($question->maxlength),
                'points'        => strval($question->points),
                'answers'       => $record_answers,
                'added_on'      => $dtAddedOn->format($serviceDatetimeFormat),
                'updated_on'    => $dtUpdatedOn->format($serviceDatetimeFormat),
            ]);
        }
            
        $dtAddedOn = \DateTime::createFromFormat('Y-m-d H:i:s', $quiz->added_on);
        $dtUpdatedOn = \DateTime::createFromFormat('Y-m-d H:i:s', $quiz->updated_on);
            
        array_push($data, [
            'uuid' => $quiz->uuid,
            'name' => $quiz->name,
            'text' => trim($quiz->text ? $quiz->text : ''),
            'failed' => trim($quiz->failed ? $quiz->failed : ''),
            'points' => strval($quiz->points),
            'minimum_points_required' => strval($quiz->minimum_points_required),
            'max_time' => $quiz->max_time ? $quiz->max_time : 5,
            'company_uuid' => $company->uuid,
            'company_name' => $company->name,
            'company_image' => $this->url()->fromRoute('services/storage',['type' => 'company', 'code' => $company->uuid, 'filename' => $company->image], ['force_canonical' => true]),
            'questions'     => $record_questions,
            'added_on'      => $dtAddedOn->format($serviceDatetimeFormat),
            'updated_on'    => $dtUpdatedOn->format($serviceDatetimeFormat),
        ]);
     
        return $data;
        
    }
    
    
    public function getSlideAction()
    {
        $request = $this->getRequest();
        if($request->isGet()) {
            $currentUserPlugin = $this->plugin('currentUserPlugin');
            $currentUser = $currentUserPlugin->getUser();
            
            $id = $this->params()->fromRoute('id');
            $slideMapper = MicrolearningSlideMapper::getInstance($this->adapter);
            $slide = $slideMapper->fetchOneByUuid($id);
            
            if(!$slide) {
                return new JsonModel([
                    'success' => false,
                    'data' => 'ERROR_SLIDE_NOT_FOUND'
                ]);
            }
            
            $accessGrantedIds = $this->getAccessGranted();
            
            
            
            if(!in_array($slide->capsule_id, $accessGrantedIds->capsules)) {
                return new JsonModel([
                    'success' => false,
                    'data' => 'ERROR_YOU_DO_NOT_HAVE_ACCESS_TO_THIS_CAPSULE'
                ]);
            }
            
            $slideMapper = MicrolearningSlideMapper::getInstance($this->adapter);
            $userProgressMapper = MicrolearningUserProgressMapper::getInstance($this->adapter);
            
            $userProgress = $userProgressMapper->fetchOneByUserIdAndSlideId($currentUser->id, $slide->id);
            if($userProgress) {
                $completed = $userProgress->completed;
            } else {
                $completed = 0;
            }
            
            $quiz_uuid = '';
            $quiz_data = [];
            $link_take_a_test = '';
            if($slide->quiz_id) {
            
                $quizMapper = MicrolearningQuizMapper::getInstance($this->adapter);
                $quiz = $quizMapper->fetchOne($slide->quiz_id);
                if($quiz) {
                    $quiz_uuid = $quiz->uuid;
                    $quiz_data = $this->getQuiz($slide->quiz_id);
                    $link_take_a_test = $this->url()->fromRoute('microlearning/take-a-test', ['slide_id' => $slide->uuid], ['force_canonical' => true]);
                }
                
            } 
                
            $storage = Storage::getInstance($this->config, $this->adapter);
            $path = $storage->getPathMicrolearningSlide();

            $image = $storage->getGenericImage($path, $slide->uuid, $slide->background);
            $file = $storage->getGenericFile($path, $slide->uuid, $slide->file);
                
            $data =[
                'quiz'              => $quiz_uuid,
                'quiz_data'         => $quiz_data,
                'uuid'              => $slide->uuid,
                'name'              => $slide->name ? $slide->name : '',
                'description'       => $slide->description ? $slide->description : '',
                'type'              => $slide->type,
                'background'        => $image,
                'file'              => $file,
                'order'             => $slide->order,
                'completed'         => $completed,
                'link_take_a_test'  => $link_take_a_test,
                'added_on'          => $slide->added_on,
                'updated_on'        => $slide->updated_on,
            ];
                
            return new JsonModel([
                'success' => true,
                'data' => $data
            ]);
                
        } else {
            return new JsonModel([
                'success' => false,
                'data' => 'ERROR_METHOD_NOT_ALLOWED'
            ]);
        }
    }
    
    public function profileAction()
    {
        $request = $this->getRequest();
        if($request->isGet()) {
            $currentUserPlugin = $this->plugin('currentUserPlugin');
            $currentUser = $currentUserPlugin->getUser();
            
            
            $accessGrantedIds = $this->getAccessGranted();
            
            $companyMapper = CompanyMapper::getInstance($this->adapter);
            $companyExtendUserMapper = MicrolearningExtendUserMapper::getInstance($this->adapter);
            $companyExtendUserCompanyMapper = MicrolearningExtendUserCompanyMapper::getInstance($this->adapter);
            $companyExtendUserFunctionMapper = MicrolearningExtendUserFunctionMapper::getInstance($this->adapter);
            $companyExtendUserGroupMapper = MicrolearningExtendUserGroupMapper::getInstance($this->adapter);
            $companyExtendUserInstitutionMapper = MicrolearningExtendUserInstitutionMapper::getInstance($this->adapter);
            $companyExtendUserPartnerMapper = MicrolearningExtendUserPartnerMapper::getInstance($this->adapter);
            $companyExtendUserProgramMapper = MicrolearningExtendUserProgramMapper::getInstance($this->adapter);
            $companyExtendUserStudentTypeMapper = MicrolearningExtendUserStudentTypeMapper::getInstance($this->adapter);
            $companyExtendUserSectorMapper = MicrolearningExtendUserSectorMapper::getInstance($this->adapter);
            
            $storage = Storage::getInstance($this->config, $this->adapter);
           

            $data = [];
            foreach($accessGrantedIds->companies as $company_id)
            {
                $company = $companyMapper->fetchOne($company_id);
                if(!$company) {
                    continue;
                }
                
                $record = [
                    'name' => $company->name,
                    'image' => $storage->getCompanyImage($company),
                    'details' => [],
                ];
                
                $companyExtendUser = $companyExtendUserMapper->fetchOneByCompanyIdAndUserId($company->id, $currentUser->id);
                if(!$companyExtendUser) {
                    continue;
                }
                
                if($companyExtendUser->extend_company_id) {
                    
                    $extendedCompany = $companyExtendUserCompanyMapper->fetchOne($companyExtendUser->company_id);
                    if($extendedCompany) {
                        array_push($record['details'],[
                            'uuid' => $extendedCompany->uuid,
                            'label' => 'LABEL_COMPANY',
                            'value' => $extendedCompany->name
                        ]);
                    }
                }
                
                if($companyExtendUser->extend_function_id) {
                    $extendedFunction = $companyExtendUserFunctionMapper->fetchOne($companyExtendUser->extend_function_id);
                    if($extendedFunction) {
                        array_push($record['details'],[
                            'uuid' => $extendedFunction->uuid,
                            'label' => 'LABEL_FUNCTION',
                            'value' => $extendedFunction->name
                        ]);
                    }
                }
                
                if($companyExtendUser->extend_group_id) {
                    $extendedGroup = $companyExtendUserGroupMapper->fetchOne($companyExtendUser->extend_group_id);
                    if($extendedGroup) {
                        array_push($record['details'],[
                            'uuid' => $extendedGroup->uuid,
                            'label' => 'LABEL_GROUP',
                            'value' => $extendedGroup->name
                        ]);
                    }
                }
                
                if($companyExtendUser->extend_institution_id) {
                    $extendedInstitution= $companyExtendUserInstitutionMapper->fetchOne($companyExtendUser->extend_institution_id);
                    if($extendedInstitution) {
                        array_push($record['details'],[
                            'uuid' => $extendedInstitution->uuid,
                            'label' => 'LABEL_INSTITUTION',
                            'value' => $extendedInstitution->name
                        ]);
                    }
                }
                
                if($companyExtendUser->extend_program_id) {
                    $extendedProgram = $companyExtendUserProgramMapper->fetchOne($companyExtendUser->extend_program_id);
                    if($extendedProgram) {
                        array_push($record['details'],[
                            'uuid' => $extendedProgram->uuid,
                            'label' => 'LABEL_PROGRAM',
                            'value' => $extendedProgram->name
                        ]);
                        
                    }
                }
                
                if($companyExtendUser->extend_sector_id) {
                    $extendedSector = $companyExtendUserSectorMapper->fetchOne($companyExtendUser->extend_sector_id);
                    if($extendedSector) {
                        array_push($record['details'],[
                            'uuid' => $extendedSector->uuid,
                            'label' => 'LABEL_SECTOR',
                            'value' => $extendedSector->name
                        ]);
                    }
                }
                
                if($companyExtendUser->extend_partner_id) {
                    $extendedPartner = $companyExtendUserPartnerMapper->fetchOne($companyExtendUser->extend_partner_id);
                    if($extendedPartner) {
                        array_push($record['details'],[
                            'uuid' => $extendedPartner->uuid,
                            'label' => 'LABEL_PARTNER',
                            'value' => $extendedPartner->name
                        ]);
                    }
                }
                
                if($companyExtendUser->extend_student_type_id) {
                    $extendedStudentType = $companyExtendUserStudentTypeMapper->fetchOne($companyExtendUser->extend_student_type_id);
                    if($extendedStudentType) {
                        array_push($record['details'],[
                            'uuid' => $extendedStudentType->uuid,
                            'label' => 'LABEL_TYPE',
                            'value' => $extendedStudentType->name
                        ]);
                    }
                }
                
                array_push($data, $record);
            }
            
            return new JsonModel([
                'success' => true,
                'data' => $data
            ]);
            
        } else {
            return new JsonModel([
                'success' => false,
                'data' => 'ERROR_METHOD_NOT_ALLOWED'
            ]);
        }
    }

    /**
     * 
     * @return \Laminas\View\Model\JsonModel
     */
    public function syncAction()
    {
        $request = $this->getRequest();
        if (!$request->isPost()) {
            return new JsonModel(['success' => false, 'data' => 'ERROR_INVALID_REQUEST']);
        }

        $slide_uuid = $this->params()->fromRoute('slide_uuid');
        $topic_uuid = $this->params()->fromRoute('topic_uuid');

        if (empty($slide_uuid) || empty($topic_uuid)) {
            return new JsonModel(['success' => false, 'data' => 'ERROR_MISSING_PARAMETERS']);
        }

        $currentUser = $this->plugin('currentUserPlugin')->getUser();
        $user_id = $currentUser->id ?? null;
        if (!$user_id) {
            return new JsonModel(['success' => false, 'data' => 'ERROR_USER_NOT_FOUND']);
        }

        $accessGrantedIds = $this->getAccessGranted();

        // Obtener Slide
        $slideMapper = MicrolearningSlideMapper::getInstance($this->adapter);
        $slide = $slideMapper->fetchOneByUuid($slide_uuid);
        if (!$slide) {
            return new JsonModel(['success' => false, 'data' => 'ERROR_SLIDE_NOT_FOUND']);
        }

        // Obtener Cápsula
        $capsuleMapper = MicrolearningCapsuleMapper::getInstance($this->adapter);
        $capsule = $capsuleMapper->fetchById($slide->capsule_id);
        if (!$capsule || !in_array($capsule->id, $accessGrantedIds->capsules)) {
            return new JsonModel(['success' => false, 'data' => 'ERROR_CAPSULE_ACCESS_DENIED']);
        }

        // Obtener Tópico
        $topicMapper = MicrolearningTopicMapper::getInstance($this->adapter);
        $topic = $topicMapper->fetchOneByUuid($topic_uuid);
        if (!$topic || !in_array($topic->id, $accessGrantedIds->topics)) {
            return new JsonModel(['success' => false, 'data' => 'ERROR_TOPIC_ACCESS_DENIED']);
        }

        // Validar que la cápsula pertenece al tópico
        $topicCapsuleMapper = MicrolearningTopicCapsuleMapper::getInstance($this->adapter);
        $relation = $topicCapsuleMapper->fetchOneByTopicIdAndCapsuleId($topic->id, $capsule->id);
        if (!$relation) {
            return new JsonModel(['success' => false, 'data' => 'ERROR_CAPSULE_DOES_NOT_BELONG_TO_TOPIC']);
        }

        // Marcar slide como visto
        $progressMapper = MicrolearningUserProgressMapper::getInstance($this->adapter);
        $progressMapper->markSlideViewed($user_id, $topic->id, $capsule->id, $slide->id);

        $data = 'LABEL_THE_USER_PROGRESS_FOR_THIS_SLIDE_HAS_BEEN_COMPLETED';

        // Si vio todos los slides → marcar cápsula como completada
        if ($progressMapper->hasViewedAllSlidesInCapsule($user_id, $capsule->id)) {
            $progressMapper->markCapsuleCompleted($user_id, $topic->id, $capsule->id);
            $data = 'LABEL_THE_USER_PROGRESS_FOR_THIS_CAPSULE_HAS_BEEN_COMPLETED';
        }

        // Si completó todas las cápsulas del tópico → marcar tópico como completado
        if ($progressMapper->hasCompletedAllCapsulesInTopic($user_id, $topic->id)) {
            $progressMapper->markTopicCompleted($user_id, $topic->id);
            $data = 'LABEL_THE_USER_PROGRESS_FOR_THIS_TOPIC_HAS_BEEN_COMPLETED';
        }

        return new JsonModel(['success' => true, 'data' => $data]);
    }    
    
    /**
     * 
     * @return \LeadersLinked\Controller\MicrolearningUserAccessGrantedIds
     */
    private function getAccessGranted()
    {
        $currentUserPlugin = $this->plugin('currentUserPlugin');
        $currentUser = $currentUserPlugin->getUser();
        
        $capsuleUserMapper = MicrolearningCapsuleUserMapper::getInstance($this->adapter);
        $now = $capsuleUserMapper->getDatebaseNow();
        
        $records = $capsuleUserMapper->fetchAllActiveByUserId($currentUser->id);
        
        $accessGrantedIds = new MicrolearningUserAccessGrantedIds();
        
        
        foreach($records as $record)
        {
            if($record->access != MicrolearningCapsuleUser::ACCESS_UNLIMITED && $record->access != MicrolearningCapsuleUser::ACCESS_PAY_PERIOD) {
                continue;
            }
            if($record->access == MicrolearningCapsuleUser::ACCESS_PAY_PERIOD) {
                if($now < $record->paid_from || $now > $record->paid_to) {
                    continue;
                }
            }
            
            
            if(!in_array($record->company_id, $accessGrantedIds->companies )) {
                array_push($accessGrantedIds->companies, $record->company_id);
            }
            
            if(!in_array($record->topic_id, $accessGrantedIds->topics )) {
                array_push( $accessGrantedIds->topics, $record->topic_id);
            }
            
            if(!in_array($record->capsule_id, $accessGrantedIds->capsules)) {
                array_push( $accessGrantedIds->capsules, $record->capsule_id);
            }
        }
        
        return $accessGrantedIds;
    }
    
    /**
     * Marks a slide as completed and cascades completion status to capsule and topic if needed
     * 
     * @return \Laminas\View\Model\JsonModel
     */
    public function completeSlideAction()
    {
        $request = $this->getRequest();
        if($request->isPost()) {
            $currentUserPlugin = $this->plugin('currentUserPlugin');
            $currentUser = $currentUserPlugin->getUser();
            
            $slide_uuid = $this->params()->fromRoute('slide_uuid');
            $topic_uuid = $this->params()->fromRoute('topic_uuid');
            $capsule_uuid = $this->params()->fromRoute('capsule_uuid');

            if(empty($slide_uuid) || empty($topic_uuid) || empty($capsule_uuid)) {
                return new JsonModel([
                    'success' => false,
                    'data' => 'ERROR_INVALID_PARAMETERS'
                ]);
            }

            // Get slide
            $slideMapper = MicrolearningSlideMapper::getInstance($this->adapter);
            $slide = $slideMapper->fetchOneByUuid($slide_uuid);

            if(!$slide) {
                return new JsonModel([
                    'success' => false,
                    'data' => 'ERROR_SLIDE_NOT_FOUND'
                ]);
            }

            // Get capsule
            $capsuleMapper = MicrolearningCapsuleMapper::getInstance($this->adapter);
            $capsule = $capsuleMapper->fetchOneByUuid($capsule_uuid);

            if(!$capsule) {
                return new JsonModel([
                    'success' => false,
                    'data' => 'ERROR_CAPSULE_NOT_FOUND'
                ]);
            }

            // Get topic
            $topicMapper = MicrolearningTopicMapper::getInstance($this->adapter);
            $topic = $topicMapper->fetchOneByUuid($topic_uuid);

            if(!$topic) {
                return new JsonModel([
                    'success' => false,
                    'data' => 'ERROR_TOPIC_NOT_FOUND'
                ]);
            }

            // Update slide progress
            $userProgressMapper = MicrolearningUserProgressMapper::getInstance($this->adapter);
            $slideProgress = $userProgressMapper->fetchOneByUserIdAndSlideId($currentUser->id, $slide->id);
            $updated_on = $userProgressMapper->getDatebaseNow();
            
            if(!$slideProgress) {
                $slideProgress = new MicrolearningUserProgress();
                $slideProgress->user_id = $currentUser->id;
                $slideProgress->slide_id = $slide->id;
                $slideProgress->topic_id = $topic->id;
                $slideProgress->capsule_id = $capsule->id;
            }

            $slideProgress->completed = 1;
            $slideProgress->updated_on = $updated_on;

            if($userProgressMapper->update($slideProgress)) {
                $closeCapsule = false;
                $closeTopic = false;
            }

            // Check if capsule is completed
            $capsuleProgress = $userProgressMapper->fetchOneByUserIdAndCapsuleId($currentUser->id, $capsule->id);

            $capsuleProgress->total_slides = $slideMapper->fetchTotalCountByCompanyIdAndCapsuleId($capsule->company_id, $capsule->id);
            $capsuleProgress->view_slides = $userProgressMapper->fetchCountAllSlideCompletedByUserIdAndCapsuleId($currentUser->id, $capsule->id);
            
            if($capsuleProgress->total_slides) {
                $capsuleProgress->progress = ($capsuleProgress->view_slides * 100) / $capsuleProgress->total_slides;
                $capsuleProgress->progress = $capsuleProgress->progress > 100 ? 100 : $capsuleProgress->progress;
            } 
            
            if(!$userProgressMapper->update($capsuleProgress)) {
                return new JsonModel([
                    'success' => false,
                    'data' => $userProgressMapper->getError()
                ]);
            }
             
            if($capsuleProgress->progress >= 100) {
                $closeCapsule = true;
            }

            // Check if topic is completed
            $topicProgress = $userProgressMapper->fetchOneByUserIdAndTopicId($currentUser->id, $topic->id);
            if($topicProgress->completed) {
                $closeTopic = true;
            }
            

            // Prepare response
            $data = 'LABEL_THE_USER_PROGRESS_FOR_THIS_SLIDE_HAS_BEEN_COMPLETED';

            if($closeCapsule) {
                $data = 'LABEL_THE_USER_PROGRESS_FOR_THIS_CAPSULE_HAS_BEEN_COMPLETED';
            }

            if($closeTopic) {
                $data = 'LABEL_THE_USER_PROGRESS_FOR_THIS_TOPIC_HAS_BEEN_COMPLETED';
            }

            return new JsonModel([
                'success' => true,
                'data' => $data
            ]);
        }

        return new JsonModel([
            'success' => false,
            'data' => 'ERROR_METHOD_NOT_ALLOWED'
        ]);
    }
}