<?php
/**
 * Assignment model.
 *
 * @since 2.3.5
 *
 * @package Masteriyo\Models;
 */

namespace Masteriyo\Addons\Assignment\Models;

use Masteriyo\Database\Model;
use Masteriyo\Addons\Assignment\Repository\AssignmentRepository;
use Masteriyo\Enums\VideoSource;
use Waynestate\Youtube\ParseId;

defined( 'ABSPATH' ) || exit;

/**
 * Assignment model (post type).
 *
 * @since 2.3.5
 */
class Assignment extends Model {

	/**
	 * This is the name of this object type.
	 *
	 * @since 2.3.5
	 *
	 * @var string
	 */
	protected $object_type = 'assignment';

	/**
	 * Post type.
	 *
	 * @since 2.3.5
	 *
	 * @var string
	 */
	protected $post_type = 'mto-assignment';

	/**
	 * Cache group.
	 *
	 * @since 2.3.5
	 *
	 * @var string
	 */
	protected $cache_group = 'assignments';

	/**
	 * Stores assignment data.
	 *
	 * @since 2.3.5
	 *
	 * @var array
	 */
	protected $data = array(
		'name'                 => '',
		'answer'               => '',
		'menu_order'           => 0,
		'parent_id'            => 0,
		'course_id'            => 0,
		'author_id'            => 0,
		'created_at'           => null,
		'modified_at'          => null,
		'status'               => false,
		'total_points'         => 100,
		'pass_points'          => 40,
		'due_date'             => null,
		'due_timestamp'        => 0,
		'max_file_upload_size' => 5, // MB
		'download_materials'   => array(),
		'video_source'         => '',
		'video_source_url'     => '',
	);

	/**
	 * Get the assignment if ID
	 *
	 * @since 2.3.5
	 *
	 * @param AssignmentRepository $assignment_repository Assignment Repository.
	 */
	public function __construct( AssignmentRepository $assignment_repository ) {
		$this->repository = $assignment_repository;
	}

	/*
	|--------------------------------------------------------------------------
	| Non-CRUD Getters
	|--------------------------------------------------------------------------
	*/

	/**
	 * Get the course's title. For courses this is the course name.
	 *
	 * @since 2.3.5
	 *
	 * @return string
	 */
	public function get_title() {
		/**
		 * Filters assignment title.
		 *
		 * @since 2.3.5
		 *
		 * @param string $title Assignment title.
		 * @param Masteriyo\Models\Assignment $assignment Assignment object.
		 */
		return apply_filters( 'masteriyo_assignment_title', $this->get_name(), $this );
	}

	/**
	 * Get assignment description.
	 *
	 * @since  2.3.5
	 *
	 * @param  string $context What the value is for. Valid values are view and edit.
	 *
	 * @return string
	 */
	public function get_description( $context = 'view' ) {
		return $this->get_answer( $context );
	}

	/**
	 * Assignment permalink.
	 *
	 * @return string
	 */
	public function get_permalink() {
		return get_permalink( $this->get_id() );
	}

	/**
	 * Get the object type.
	 *
	 * @since 2.3.5
	 *
	 * @return string
	 */
	public function get_object_type() {
		return $this->object_type;
	}

	/**
	 * Get the post type.
	 *
	 * @since 2.3.5
	 *
	 * @return string
	 */
	public function get_post_type() {
		return 'mto-assignment';
	}

	/**
	 * Get post preview link.
	 *
	 * @since 2.3.5
	 *
	 * @return string
	 */
	public function get_post_preview_link() {
		$preview_link = get_preview_post_link( $this->get_id() );

		/**
		 * Assignment post preview link.
		 *
		 * @since 2.3.5
		 *
		 * @param string $url Preview URL.
		 * @param Masteriyo\Models\Assignment $assignment Assignment object.
		 */
		return apply_filters( 'masteriyo_assignment_post_preview_link', $preview_link, $this );
	}

	/**
	 * Get preview link in learn page.
	 *
	 * @since 2.3.5
	 *
	 * @return string
	 */
	public function get_preview_link() {
		$preview_link = '';
		$course       = masteriyo_get_course( $this->get_course_id() );

		if ( $course ) {
			$course_preview_link = $course->get_preview_link( false );
			$preview_link        = trailingslashit( $course_preview_link ) . 'assignment/' . $this->get_id();
		}

		/**
		 * Assignment preview link for learn page.
		 *
		 * @since 2.3.5
		 *
		 * @param string $url Preview URL.
		 * @param Masteriyo\Models\Assignment $assignment Assignment object.
		 */
		return apply_filters( 'masteriyo_assignment_preview_link', $preview_link, $this );
	}


	/**
	 * Get icon.
	 *
	 * @since 2.3.5
	 *
	 * @return string
	 */
	public function get_icon( $context = 'single-course.curriculum.section.content' ) {
		$icon = masteriyo_get_svg( 'assignment' );

		/**
		 * Filters assignment icon.
		 *
		 * @since 2.5.10
		 *
		 * @param string $icon.
		 * @param string $context.
		 */
		return apply_filters( 'masteriyo_assignment_icon', $icon, $context );
	}

	/*
	|--------------------------------------------------------------------------
	| Getters
	|--------------------------------------------------------------------------
	*/

	/**
	 * Get assignment name.
	 *
	 * @since  2.3.5
	 *
	 * @param  string $context What the value is for. Valid values are view and edit.
	 *
	 * @return string
	 */
	public function get_name( $context = 'view' ) {
		/**
		 * Filters assignment name.
		 *
		 * @since 2.3.5
		 *
		 * @param string $name Assignment name.
		 * @param \Masteriyo\Models\Assignment $assignment Assignment object.
		 */
		return apply_filters( 'masteriyo_assignment_name', $this->get_prop( 'name', $context ), $this );
	}

	/**
	 * Get assignment created date.
	 *
	 * @since  2.3.5
	 *
	 * @param  string $context What the value is for. Valid values are view and edit.
	 *
	 * @return DateTime|NULL object if the date is set or null if there is no date.
	 */
	public function get_created_at( $context = 'view' ) {
		return $this->get_prop( 'created_at', $context );
	}

	/**
	 * Get assignment modified date.
	 *
	 * @since  2.3.5
	 *
	 * @param  string $context What the value is for. Valid values are view and edit.
	 *
	 * @return DateTime|NULL object if the date is set or null if there is no date.
	 */
	public function get_modified_at( $context = 'view' ) {
		return $this->get_prop( 'modified_at', $context );
	}

	/**
	 * Get download_materials.
	 *
	 * @since 2.12.0
	 *
	 * @param string $context What the value is for. Valid values are view and edit.
	 *
	 * @return array
	 */
	public function get_download_materials( $context = 'view' ) {
		return $this->get_prop( 'download_materials', $context );
	}

	/**
	 * Get assignment answer.
	 *
	 * @since  2.3.5
	 *
	 * @param  string $context What the value is for. Valid values are view and edit.
	 *
	 * @return string
	 */
	public function get_answer( $context = 'view' ) {
		return $this->get_prop( 'answer', $context );
	}

	/**
	 * Returns assignment parent id.
	 *
	 * @since  2.3.5
	 *
	 * @param  string $context What the value is for. Valid values are view and edit.
	 *
	 * @return string
	 */
	public function get_parent_id( $context = 'view' ) {
		return $this->get_prop( 'parent_id', $context );
	}

	/**
	 * Returns the assignment's course id.
	 *
	 * @since  2.3.5
	 *
	 * @param  string $context What the value is for. Valid values are view and edit.
	 *
	 * @return string
	 */
	public function get_course_id( $context = 'view' ) {
		return $this->get_prop( 'course_id', $context );
	}

	/**
	 * Returns the assignment's author id.
	 *
	 * @since  2.3.5
	 *
	 * @param  string $context What the value is for. Valid values are view and edit.
	 *
	 * @return string
	 */
	public function get_author_id( $context = 'view' ) {
		return $this->get_prop( 'author_id', $context );
	}

	/**
	 * Returns assignment menu order.
	 *
	 * @since  2.3.5
	 *
	 * @param  string $context What the value is for. Valid values are view and edit.
	 *
	 * @return string
	 */
	public function get_menu_order( $context = 'view' ) {
		return $this->get_prop( 'menu_order', $context );
	}

	/**
	 * Get assignment status.
	 *
	 * @since  2.3.5
	 *
	 * @param  string $context What the value is for. Valid values are view and edit.
	 *
	 * @return string
	 */
	public function get_status( $context = 'view' ) {
		return $this->get_prop( 'status', $context );
	}

	/**
	 * Get assignment total points.
	 *
	 * @since  2.3.5
	 *
	 * @param  string $context What the value is for. Valid values are view and edit.
	 *
	 * @return int
	 */
	public function get_total_points( $context = 'view' ) {
		return $this->get_prop( 'total_points', $context );
	}

	/**
	 * Get assignment pass points.
	 *
	 * @since  2.3.5
	 *
	 * @param  string $context What the value is for. Valid values are view and edit.
	 *
	 * @return int
	 */
	public function get_pass_points( $context = 'view' ) {
		return $this->get_prop( 'pass_points', $context );
	}

	/**
	 * Get assignment due_date.
	 *
	 * @since  2.3.5
	 *
	 * @param  string $context What the value is for. Valid values are view and edit.
	 *
	 * @return DateTime|NULL object if the date is set or null if there is no date.
	 */
	public function get_due_date( $context = 'view' ) {
		return $this->get_prop( 'due_date', $context );
	}


	/**
	 * Get assignment due timestamp.
	 *
	 * @since  2.3.5
	 *
	 * @param  string $context What the value is for. Valid values are view and edit.
	 *
	 * @return int
	 */
	public function get_due_timestamp( $context = 'view' ) {
		return $this->get_prop( 'due_timestamp', $context );
	}

	/**
	 * Get assignment max file upload size.
	 *
	 * @since  2.3.5
	 *
	 * @param  string $context What the value is for. Valid values are view and edit.
	 *
	 * @return string
	 */
	public function get_max_file_upload_size( $context = 'view' ) {
		return $this->get_prop( 'max_file_upload_size', $context );
	}

	/**
	 * Get video source.
	 *
	 * @since 2.15.0
	 *
	 * @param string $context What the value is for. Valid values are view and edit.
	 *
	 * @return string
	 */
	public function get_video_source( $context = 'view' ) {
		return $this->get_prop( 'video_source', $context );
	}

	/**
	 * Get video source.
	 *
	 * @since 2.15.0
	 *
	 * @param string $context What the value is for. Valid values are view and edit.
	 *
	 * @return string
	 */
	public function get_video_source_url( $context = 'view' ) {
		$source     = $this->get_video_source( 'edit' );
		$source_url = trim( $this->get_prop( 'video_source_url', $context ) );

		if ( 'edit' === $context ) {
			return $source_url;
		}

		if ( VideoSource::SELF_HOSTED === $source && is_numeric( $source_url ) ) {
			$video_url_type = masteriyo_get_setting( 'learn_page.general.lesson_video_url_type' );
			if ( 'default' === $video_url_type ) {
				$source_url = wp_get_attachment_url( $this->get_video_source_id( $context ) );
			} else {
				$source_url = masteriyo_generate_self_hosted_lesson_video_url( $this->get_id() );
			}
		}

		return $source_url;
	}

	/**
	 * Get video source id.
	 *
	 * @since 2.15.0
	 *
	 * @param string $context What the value is for. Valid values are view and edit.
	 *
	 * @return int
	 */
	public function get_video_source_id( $context = 'view' ) {
		return absint( $this->get_prop( 'video_source_url', $context ) );
	}

	/**
	 * Get video meta info for masteriyo player.
	 *
	 * @since 2.15.0
	 *
	 * @param string $context What the value is for. Valid values are view and edit.
	 *
	 * @return int
	 */
	public function get_video_meta( $context = 'view' ) {
		return $this->get_prop( 'video_meta', $context );
	}

	/**
	 * Get embed URL for the featured video. If the video source is self-hosted, it will return the absolute URL to the file.
	 *
	 * @since 2.15.0
	 *
	 * @return string
	 */
	public function get_video_source_embed_url() {
		$featured_video_source = $this->get_video_source();
		$video_id              = $this->get_video_id();
		$embed_url             = '';

		if ( VideoSource::SELF_HOSTED === $featured_video_source || VideoSource::EXTERNAL === $featured_video_source ) {
			$embed_url = $this->get_video_source_url();
		} elseif ( VideoSource::YOUTUBE === $featured_video_source ) {
			$embed_url = 'https://www.youtube.com/embed/' . $video_id;
		} elseif ( VideoSource::VIMEO === $featured_video_source ) {
			$embed_url = 'https://player.vimeo.com/video/' . $video_id;
		}

		/**
		 * Filters video embed URL of a assignment.
		 *
		 * @since 2.15.0
		 *
		 * @param string $embed_url
		 * @param \Masteriyo\Models\Assignment $assignment
		 */
		return apply_filters( 'masteriyo_assignment_video_embed_url', $embed_url, $this );
	}

	/**
	 * Get the id of featured video.
	 *
	 * @since 2.15.0
	 *
	 * @return string|number
	 */
	public function get_video_id() {
		$featured_video_source = $this->get_video_source();
		$featured_video_url    = $this->get_video_source_url();
		$video_id              = 0;

		if ( VideoSource::YOUTUBE === $featured_video_source ) {
			$video_id = ParseId::fromUrl( $featured_video_url );
		} elseif ( VideoSource::VIMEO === $featured_video_source ) {
			$video_id = masteriyo_get_vimeo_id_from_url( $featured_video_url );
		}

		/**
		 * Filters video id of a assignment.
		 *
		 * @since 2.15.0
		 *
		 * @param int $video_id
		 * @param \Masteriyo\Models\Assignment $assignment
		 */
		return apply_filters( 'masteriyo_assignment_video_id', $video_id, $this );
	}


	/**
	 * Get video playback time.
	 *
	 * @since 2.15.0
	 *
	 * @param int $context What the value is for. Valid values are view and edit.
	 *
	 * @return int
	 */
	public function get_video_playback_time( $context = 'view' ) {
		return $this->get_prop( 'video_playback_time', $context );
	}


	/*
	|--------------------------------------------------------------------------
	| Setters
	|--------------------------------------------------------------------------
	*/

	/**
	 * Set assignment name.
	 *
	 * @since 2.3.5
	 *
	 * @param string $name assignment name.
	 */
	public function set_name( $name ) {
		$this->set_prop( 'name', $name );
	}

	/**
	 * Set assignment created date.
	 *
	 * @since 2.3.5
	 *
	 * @param string|integer|null $date UTC timestamp, or ISO 8601 DateTime. If the DateTime string has no timezone or offset, WordPress site timezone will be assumed. Null if their is no date.
	 */
	public function set_created_at( $date = null ) {
		$this->set_date_prop( 'created_at', $date );
	}

	/**
	 * Set assignment modified date.
	 *
	 * @since 2.3.5
	 *
	 * @param string|integer|null $date UTC timestamp, or ISO 8601 DateTime. If the DateTime string has no timezone or offset, WordPress site timezone will be assumed. Null if their is no date.
	 */
	public function set_modified_at( $date = null ) {
		$this->set_date_prop( 'modified_at', $date );
	}

	/**
	 * Set assignment answer.
	 *
	 * @since 2.3.5
	 *
	 * @param string $answer Assignment answer.
	 */
	public function set_answer( $answer ) {
		$this->set_prop( 'answer', $answer );
	}

	/**
	 * Set the assignment parent id.
	 *
	 * @since 2.3.5
	 *
	 * @param int $parent Parent id.
	 */
	public function set_parent_id( $parent ) {
		$this->set_prop( 'parent_id', absint( $parent ) );
	}

	/**
	 * Set the assignment's course id.
	 *
	 * @since 2.3.5
	 *
	 * @param int $course_id Course id.
	 */
	public function set_course_id( $course_id ) {
		$this->set_prop( 'course_id', absint( $course_id ) );
	}

	/**
	 * Set download_materials.
	 *
	 * @since 2.12.0
	 *
	 * @param array $download_materials Download materials.
	 */
	public function set_download_materials( $download_materials ) {
		$this->set_prop( 'download_materials', $download_materials );
	}

	/**
	 * Set the assignment's author id.
	 *
	 * @since 2.3.5
	 *
	 * @param int $author_id author id.
	 */
	public function set_author_id( $author_id ) {
		$this->set_prop( 'author_id', absint( $author_id ) );
	}

	/**
	 * Set the assignment menu order.
	 *
	 * @since 2.3.5
	 *
	 * @param int $menu_order Menu order id.
	 */
	public function set_menu_order( $menu_order ) {
		$this->set_prop( 'menu_order', absint( $menu_order ) );
	}

	/**
	 * Set assignment status.
	 *
	 * @since 2.3.5
	 *
	 * @param string $status Assignment status.
	 */
	public function set_status( $status ) {
		$this->set_prop( 'status', $status );
	}

	/**
	 * Set assignment total points.
	 *
	 * @since 2.3.5
	 *
	 * @param int $total_points Assignment total_points.
	 */
	public function set_total_points( $total_points ) {
		$this->set_prop( 'total_points', absint( $total_points ) );
	}

	/**
	 * Set assignment pass points.
	 *
	 * @since 2.3.5
	 *
	 * @param int $pass_points Assignment pass_points.
	 */
	public function set_pass_points( $pass_points ) {
		$this->set_prop( 'pass_points', absint( $pass_points ) );
	}

	/**
	 * Set assignment due date.
	 *
	 * @since 2.3.5
	 *
	 * @param string $due_date Assignment due date.
	 */
	public function set_due_date( $due_date ) {
		$this->set_date_prop( 'due_date', $due_date );
	}

	/**
	 * Set assignment due timestamp.
	 *
	 * @since 2.3.5
	 *
	 * @param string $due_timestamp Assignment due timestamp.
	 */
	public function set_due_timestamp( $due_timestamp ) {
		$this->set_prop( 'due_timestamp', absint( $due_timestamp ) );
	}

	/**
	 * Set assignment max file upload size.
	 *
	 * @since 2.3.5
	 *
	 * @param int $max_file_upload_size Assignment max_file_upload_size.
	 */
	public function set_max_file_upload_size( $max_file_upload_size ) {
		$this->set_prop( 'max_file_upload_size', absint( $max_file_upload_size ) );
	}

	/**
	 * Set video source.
	 *
	 * @since 2.15.0
	 *
	 * @param string $video_source Video source.
	 */
	public function set_video_source( $video_source ) {
		$this->set_prop( 'video_source', $video_source );
	}

	/**
	 * Set video source url.
	 *
	 * @since 2.15.0
	 *
	 * @param string $video_source_url Video source url.
	 */
	public function set_video_source_url( $video_source_url ) {
		$this->set_prop( 'video_source_url', trim( $video_source_url ) );
	}

	/**
	 * Set video meta info for masteriyo player.
	 *
	 * @since 2.15.0
	 *
	 * @param array $video_meta The array video meta info like timestamps, notes, enable_video_share, etc.
	 */
	public function set_video_meta( $video_meta ) {
		$this->set_prop( 'video_meta', $video_meta );
	}
}
