<?php
/**
 * Capabilities Management
 *
 * Handles custom capabilities for video uploads and management.
 * Supports both admin and instructor roles.
 *
 * @package KursBooking
 * @since   1.3.0
 */

declare(strict_types=1);

// Prevent direct access.
if ( ! defined( 'ABSPATH' ) ) {
	exit;
}

/**
 * Class Kurs_Booking_Capabilities
 *
 * Manages custom capabilities for the plugin.
 */
class Kurs_Booking_Capabilities {

	/**
	 * Custom capabilities
	 */
	public const CAP_UPLOAD_VIDEOS = 'upload_kurs_videos';
	public const CAP_MANAGE_VIDEOS = 'manage_kurs_videos';
	public const CAP_MANAGE_KURSE  = 'manage_kurs_booking';

	/**
	 * Initialize capabilities
	 */
	public static function init(): void {
		// Filter capabilities.
		add_filter( 'user_has_cap', array( __CLASS__, 'filter_user_capabilities' ), 10, 4 );

		// Maybe add capabilities to roles on plugin update.
		add_action( 'admin_init', array( __CLASS__, 'maybe_add_caps_to_roles' ) );
	}

	/**
	 * Filter user capabilities dynamically
	 *
	 * This grants capabilities to users based on their roles without
	 * permanently modifying the role definitions.
	 *
	 * @param array<string, bool> $allcaps All capabilities.
	 * @param array<int, string>  $caps    Required capabilities.
	 * @param array<int, mixed>   $args    Capability arguments.
	 * @param WP_User             $user    User object.
	 * @return array<string, bool> Modified capabilities.
	 */
	public static function filter_user_capabilities( array $allcaps, array $caps, array $args, WP_User $user ): array {
		// Administrator always has all plugin capabilities.
		if ( ! empty( $allcaps['manage_options'] ) ) {
			$allcaps[ self::CAP_UPLOAD_VIDEOS ] = true;
			$allcaps[ self::CAP_MANAGE_VIDEOS ] = true;
			$allcaps[ self::CAP_MANAGE_KURSE ]  = true;
			return $allcaps;
		}

		// Editor can upload videos but not manage all.
		if ( ! empty( $allcaps['edit_others_posts'] ) ) {
			$allcaps[ self::CAP_UPLOAD_VIDEOS ] = true;
			$allcaps[ self::CAP_MANAGE_KURSE ]  = true;
			return $allcaps;
		}

		// Check if user is a course instructor (author of kurse).
		if ( self::is_kurs_instructor( $user->ID ) ) {
			$allcaps[ self::CAP_UPLOAD_VIDEOS ] = true;
		}

		return $allcaps;
	}

	/**
	 * Check if user is a course instructor
	 *
	 * A user is considered an instructor if they are the author of at least one kurs.
	 *
	 * @param int $user_id User ID.
	 * @return bool True if user is an instructor.
	 */
	public static function is_kurs_instructor( int $user_id ): bool {
		static $cache = array();

		if ( isset( $cache[ $user_id ] ) ) {
			return $cache[ $user_id ];
		}

		global $wpdb;

		// Check if user has authored any kurse.
		$count = $wpdb->get_var(
			$wpdb->prepare(
				"SELECT COUNT(*) FROM {$wpdb->posts}
				WHERE post_type = 'kurs'
				AND post_author = %d
				AND post_status IN ('publish', 'draft', 'private')",
				$user_id
			)
		);

		$cache[ $user_id ] = $count > 0;

		return $cache[ $user_id ];
	}

	/**
	 * Maybe add capabilities to roles
	 *
	 * This runs once on plugin activation or update.
	 */
	public static function maybe_add_caps_to_roles(): void {
		$version_key = 'kurs_booking_caps_version';
		$current_version = get_option( $version_key, '0' );

		// Only run once per version.
		if ( version_compare( $current_version, '1.3.0', '>=' ) ) {
			return;
		}

		// Add capabilities to administrator.
		$admin = get_role( 'administrator' );
		if ( $admin ) {
			$admin->add_cap( self::CAP_UPLOAD_VIDEOS );
			$admin->add_cap( self::CAP_MANAGE_VIDEOS );
			$admin->add_cap( self::CAP_MANAGE_KURSE );
		}

		// Add upload capability to editor.
		$editor = get_role( 'editor' );
		if ( $editor ) {
			$editor->add_cap( self::CAP_UPLOAD_VIDEOS );
			$editor->add_cap( self::CAP_MANAGE_KURSE );
		}

		update_option( $version_key, '1.3.0' );
	}

	/**
	 * Remove all custom capabilities (for uninstall)
	 */
	public static function remove_caps(): void {
		$roles = array( 'administrator', 'editor' );
		$caps  = array(
			self::CAP_UPLOAD_VIDEOS,
			self::CAP_MANAGE_VIDEOS,
			self::CAP_MANAGE_KURSE,
		);

		foreach ( $roles as $role_name ) {
			$role = get_role( $role_name );
			if ( $role ) {
				foreach ( $caps as $cap ) {
					$role->remove_cap( $cap );
				}
			}
		}

		delete_option( 'kurs_booking_caps_version' );
	}

	/**
	 * Check if current user can upload videos
	 *
	 * @return bool
	 */
	public static function can_upload_videos(): bool {
		return current_user_can( self::CAP_UPLOAD_VIDEOS );
	}

	/**
	 * Check if current user can manage all videos
	 *
	 * @return bool
	 */
	public static function can_manage_videos(): bool {
		return current_user_can( self::CAP_MANAGE_VIDEOS );
	}

	/**
	 * Check if user can edit a specific video
	 *
	 * @param int      $video_id Video post ID.
	 * @param int|null $user_id  User ID (default: current user).
	 * @return bool
	 */
	public static function can_edit_video( int $video_id, ?int $user_id = null ): bool {
		if ( null === $user_id ) {
			$user_id = get_current_user_id();
		}

		// Admin can edit all.
		if ( user_can( $user_id, self::CAP_MANAGE_VIDEOS ) ) {
			return true;
		}

		// Check if user is author.
		$video = get_post( $video_id );
		if ( ! $video ) {
			return false;
		}

		return (int) $video->post_author === $user_id;
	}

	/**
	 * Check if user can view a specific video
	 *
	 * @param int      $video_id Video post ID.
	 * @param int|null $user_id  User ID (default: current user).
	 * @return bool
	 */
	public static function can_view_video( int $video_id, ?int $user_id = null ): bool {
		if ( null === $user_id ) {
			$user_id = get_current_user_id();
		}

		// Admin can view all.
		if ( user_can( $user_id, self::CAP_MANAGE_VIDEOS ) ) {
			return true;
		}

		// Check if user is author.
		$video = get_post( $video_id );
		if ( ! $video ) {
			return false;
		}

		if ( (int) $video->post_author === $user_id ) {
			return true;
		}

		// Check if user is instructor of any assigned kurs.
		$kurse = Kurs_Booking_Video::get_video_kurse( $video_id );
		foreach ( $kurse as $kurs ) {
			if ( (int) $kurs->post_author === $user_id ) {
				return true;
			}
		}

		return false;
	}
}
