<?php
/**
 * OrokuBlocks - GamiPress Integration
 * 
 * @package OrokuBlocks
 * @author OrokuBlocks (https://orokublocks.com/)
 * 
 * @since 1.0.0
 * 
 */

// Exit if accessed directly
if ( ! defined( 'ABSPATH' ) ) {
  exit;
}

final class OrokuBlocks_Gamipress {
  /**
   * Prevent more than one instance from being created
   * 
   * @since 1.0.0
   * 
   * @access private
   */
  private function __construct() {}

  /**
   * Prevent cloning
   * 
   * @since 1.0.0
   * 
   * @access private
   */
  private function __clone() {}

  /**
   * Returns achievement, point or rank thumbnail url.
   * 
   * @since 1.0.0
   * 
   * @param int     $post_id            Id of the achievement, point or rank to get the thumbnail of.
   * @return string $thumbnail_url      Achievement, point or rank thumbnail url.
   */
  public static function postThumbnailUrlGet( $post_id ) {
    $thumbnail_url = '';

    if ( is_multisite() ) {
      $site_id = gamipress_is_network_wide_active() ? get_main_site_id() : get_current_blog_id();

      switch_to_blog( $site_id );
    }

    $thumbnail_post_id = get_post_thumbnail_id( $post_id );

    // if achievement, point or rank doesn't have an image assigned, check if default image exists
    if ( ! $thumbnail_post_id ) {
      // get achievement, point or rank type
      $achievement = get_page_by_path( gamipress_get_post_type( $post_id ), OBJECT, 'achievement-type' );

      if ( is_object( $achievement ) ) {
        // get achievement, point or rank type thumbnail id
        $thumbnail_post_id = get_post_thumbnail_id( $achievement->ID );
      }
    }

    // if thumbnail exists
    if ( $thumbnail_post_id !== 0 ) {
      $thumbnail_url = OrokuBlocks_Blog::thumbnailUrlGet( $thumbnail_post_id );
    }

    if ( is_multisite() ) {
      restore_current_blog();
    }

    return $thumbnail_url;
  }

  /**
   * Returns user amount of points.
   * 
   * @since 1.0.0
   * 
   * @param string  $point_slug             Slug of the point to get data from.
   * @return int    $points_amount          Amount of points the user has.   
   */
  public static function userPointsGet( $point_slug ) {
    $points_amount = 0;

    $points_amount = gamipress_get_user_points( get_current_user_id(), $point_slug );

    return $points_amount;
  }

  /**
   * Returns point data by slug.
   * 
   * @since 1.0.0
   * 
   * @param string      $point_slug         Slug of the point to get data from.
   * @return array|bool $point_data         Point data or false if not found.   
   */
  public static function pointGet( $point_slug ) {
    $point_data = false;

    $point_types = gamipress_get_points_types();

    if ( array_key_exists( $point_slug, $point_types ) ) {
      $point = $point_types[$point_slug];

      $point_id = $point['ID'];

      $point_data = [
        'id'            => $point_id,
        'singular_name' => $point['singular_name'],
        'plural_name'   => $point['plural_name'],
        'slug'          => $point_slug,
        'image_url'     => self::postThumbnailURLGet( $point_id )
      ];
    }

    return $point_data;
  }

  /**
   * Returns point modifiers (awards / deducts) data by slug.
   * 
   * @since 1.0.0
   * 
   * @param string  $point_slug           Slug of the point to get data from.
   * @param string  $point_modifier       Point modifier, one of: 'awards', 'deducts'.
   * @return array  $point_modifiers      Point modifiers.   
   */
  public static function pointModifiersGet( $point_slug, $point_modifier = '' ) {
    $point_modifiers = [];

    switch ( $point_modifier ) {
      case 'deducts':
        $modifier_posts = gamipress_get_points_type_points_deducts( $point_slug );
        break;
      case 'awards':
        $modifier_posts = gamipress_get_points_type_points_awards( $point_slug );
        break;
      default:
        $modifier_posts = false;
        break;
    }

    if ( is_array( $modifier_posts ) ) {
      foreach ( $modifier_posts as $modifier_post ) {
        $point_modifiers[] = [
          'id'      => $modifier_post->ID,
          'title'   => $modifier_post->post_title,
          'points'  => intval( gamipress_get_post_meta( $modifier_post->ID, '_gamipress_points' ) ),
          'limit'   => [
            'type'    => gamipress_get_post_meta( $modifier_post->ID, '_gamipress_limit_type' ),
            'amount'  => intval( gamipress_get_post_meta( $modifier_post->ID, '_gamipress_limit' ) )
          ]
        ];
      }
    }

    return $point_modifiers;
  }

  /**
   * Returns the data of points that are awarded when completing an achievement.
   * 
   * @since 1.0.0
   * 
   * @param int         $achievement_id           Id of the achievement.
   * @return array|bool $point_data               Data of the points awarded by the achievement.
   */
  public static function achievementPointsGet( $achievement_id ) {
    $points_awarded_slug = gamipress_get_post_meta( $achievement_id, '_gamipress_points_type' );
    $points_awarded_amount = intval( gamipress_get_post_meta( $achievement_id, '_gamipress_points' ) );

    $points_awarded = [
      'amount'    => $points_awarded_amount,
      'image_url' => ''
    ];

    $point_data = self::pointGet( $points_awarded_slug );

    if ( $point_data ) {
      $points_awarded = array_merge( $points_awarded , $point_data );
    }

    return $points_awarded;
  }

  /**
   * Returns steps that need to be completed to earn an achievement.
   * 
   * @since 1.0.0
   * 
   * @param int     $achievement_id           Id of the achievement.
   * @return array  $achievement_steps        Achievement steps.
   */
  public static function achievementStepsGet( $achievement_id ) {
    $achievement_steps = [];
    $steps = gamipress_get_achievement_steps( $achievement_id );

    foreach ( $steps as $step ) {
      $achievement_steps[] = [
        'id'        => $step->ID,
        'title'     => $step->post_title,
        'complete'  => gamipress_has_user_earned_achievement( $step->ID, get_current_user_id() )
      ];
    }

    return $achievement_steps;
  }

  /**
   * Returns how many users have earned an achievement and the data of the most recent $limit earners.
   * 
   * @since 1.0.0
   * 
   * @param int     $achievement_id           Id of the achievement.
   * @param int     $limit                    Amount of last earners to retrieve user data of.
   * @return array  $achievement_earners      Achievement earners user data.
   */
  public static function achievementEarnersGet( $achievement_id, $limit = 5 ) {
    $achievement_earners = [
      'count' => count( gamipress_get_achievement_earners( $achievement_id ) ),
      'users' => []
    ];

    $achievement_earners_users = gamipress_get_achievement_earners( $achievement_id, [ 'limit' => $limit ] );

    foreach ( $achievement_earners_users as $achievement_earners_user ) {
      $achievement_earners['users'][] = [
        'id'            => $achievement_earners_user->ID,
        'user_login'    => $achievement_earners_user->user_login,
        'user_nicename' => $achievement_earners_user->user_nicename,
        'display_name'  => $achievement_earners_user->display_name,
        'image_url'     => get_avatar_url( $achievement_earners_user->ID )
      ];
    }

    return $achievement_earners;
  }

  /**
   * Return achievement data by slug or false if not found.
   * 
   * @since 1.0.0
   * 
   * @param string      $achievement_slug         Achievement slug.
   * @return array|bool $achievement_data         Achievement data or false if not found.
   */
  public static function achievementGet( $achievement_slug ) {
    $achievement_data = false;

    $args = [
      'post_name__in' => [ $achievement_slug ]
    ];

    $achievements = gamipress_get_achievements( $args );

    if ( count( $achievements ) > 0 ) {
      $achievement = $achievements[0];

      /**
       * Get achievement points
       */
      $points_awarded = self::achievementPointsGet( $achievement->ID );

      /**
       * Get achievement steps
       */
      $achievement_steps = self::achievementStepsGet( $achievement->ID );

      /**
       * Get achievement earners
       */
      $achievement_earners = self::achievementEarnersGet( $achievement->ID );

      $achievement_data = [
        'id'              => $achievement->ID,
        'slug'            => $achievement_slug,
        'title'           => $achievement->post_title,
        'content'         => $achievement->post_content,
        'image_url'       => self::postThumbnailUrlGet( $achievement->ID ),
        'points_awarded'  => $points_awarded,
        'earners'         => $achievement_earners,
        'complete'        => gamipress_has_user_earned_achievement( $achievement->ID, get_current_user_id() ),
        'steps'           => $achievement_steps
      ];
    }

    return $achievement_data;
  }

  /**
   * Returns steps that need to be completed to earn a rank.
   * 
   * @since 1.0.0
   * 
   * @param int     $rank_id            Id of the rank.
   * @return array  $rank_steps         Rank steps.
   */
  public static function rankStepsGet( $rank_id ) {
    $rank_steps = [];
    $steps = gamipress_get_rank_requirements( $rank_id );

    foreach ( $steps as $step ) {
      $rank_steps[] = [
        'id'        => $step->ID,
        'title'     => $step->post_title,
        'complete'  => gamipress_has_user_earned_achievement( $step->ID, get_current_user_id() )
      ];
    }

    return $rank_steps;
  }

  /**
   * Returns how many users have earned a rank and the data of the most recent $limit earners.
   * 
   * @since 1.0.0
   * 
   * @param int     $rank_id            Id of the rank.
   * @param int     $limit              Amount of last earners to retrieve user data of.
   * @return array  $rank_earners       Rank earners user data.
   */
  public static function rankEarnersGet( $rank_id, $limit = 5 ) {
    $rank_earners = [
      'count' => count( gamipress_get_rank_earners( $rank_id ) ),
      'users' => []
    ];

    $rank_earners_users = gamipress_get_rank_earners( $rank_id, [ 'limit' => $limit ] );

    foreach ( $rank_earners_users as $rank_earners_user ) {
      $rank_earners['users'][] = [
        'id'            => $rank_earners_user->ID,
        'user_login'    => $rank_earners_user->user_login,
        'user_nicename' => $rank_earners_user->user_nicename,
        'display_name'  => $rank_earners_user->display_name,
        'image_url'     => get_avatar_url( $rank_earners_user->ID )
      ];
    }

    return $rank_earners;
  }

  /**
   * Return rank data by slug or false if not found.
   * 
   * @since 1.0.0
   * 
   * @param string      $rank_slug         Rank slug.
   * @return array|bool $rank_data         Rank data or false if not found.
   */
  public static function rankGet( $rank_slug ) {
    $rank_data = false;

    $args = [
      'post_name__in' => [ $rank_slug ]
    ];

    $ranks = gamipress_get_ranks( $args );

    if ( count( $ranks ) > 0 ) {
      $rank = $ranks[0];

      /**
       * Get rank steps
       */
      $rank_steps = self::rankStepsGet( $rank->ID );

      /**
       * Get rank earners
       */
      $rank_earners = self::rankEarnersGet( $rank->ID );

      $rank_data = [
        'id'              => $rank->ID,
        'slug'            => $rank_slug,
        'title'           => $rank->post_title,
        'content'         => $rank->post_content,
        'image_url'       => self::postThumbnailUrlGet( $rank->ID ),
        'earners'         => $rank_earners,
        'complete'        => gamipress_is_lowest_priority_rank( $rank->ID ) || gamipress_has_user_earned_rank( $rank->ID, get_current_user_id() ),
        'steps'           => $rank_steps
      ];
    }

    return $rank_data;
  }
}