<?php declare(strict_types = 1);

namespace MailPoet\Automation\Engine;

if (!defined('ABSPATH')) exit;


use DateTimeZone;
use WP_Comment;
use WP_Error;
use WP_Locale;
use WP_Post;
use WP_Term;
use WP_User;

class WordPress {
  public function addAction(string $hookName, callable $callback, int $priority = 10, int $acceptedArgs = 1): bool {
    return add_action($hookName, $callback, $priority, $acceptedArgs);
  }

  public function removeAction(string $hookName, callable $callback, int $priority = 10): bool {
    return remove_action($hookName, $callback, $priority);
  }

  /**
   * @param non-empty-string $hookName
   * @param mixed ...$arg
   */
  public function doAction(string $hookName, ...$arg): void {
    do_action($hookName, ...$arg);
  }

  public function removeFilter(string $hookName, callable $callback, int $priority = 10): bool {
    return remove_filter($hookName, $callback, $priority);
  }

  public function addFilter(string $hookName, callable $callback, int $priority = 10, int $acceptedArgs = 1): bool {
    return add_filter($hookName, $callback, $priority, $acceptedArgs);
  }

  /**
   * @param non-empty-string $hookName
   * @param mixed $value
   * @param mixed ...$args
   * @return mixed
   */
  public function applyFilters(string $hookName, $value, ...$args) {
    return apply_filters($hookName, $value, ...$args);
  }

  public function wpTimezone(): DateTimeZone {
    return wp_timezone();
  }

  public function wpGetCurrentUser(): WP_User {
    return wp_get_current_user();
  }

  /** @param mixed ...$args */
  public function currentUserCan(string $capability, ...$args): bool {
    return current_user_can($capability, ...$args);
  }

  public function registerRestRoute(string $namespace, string $route, array $args = [], bool $override = false): bool {
    return register_rest_route($namespace, $route, $args, $override);
  }

  public function adminUrl(string $path = '', string $scheme = 'admin'): string {
    return admin_url($path, $scheme);
  }

  public function getWpLocale(): WP_Locale {
    global $wp_locale;
    return $wp_locale;
  }

  /**
   * @param 'ARRAY_A'|'ARRAY_N'|'OBJECT' $object
   * @return array|WP_Post|null
   */
  public function getPost(int $id, string $object = OBJECT) {
    return get_post($id, $object);
  }

  /** @return WP_Post[]|int[] */
  public function getPosts(?array $args = null): array {
    return get_posts($args);
  }

  /**
   * @param string|array<string, mixed> $args
   * @return WP_Comment[]|int[]|int
   */
  public function getComments($args = '') {
    /* @phpstan-ignore-next-line argument.type -- thin pass-through; WP stub declares a closed array shape that we do not enforce in this wrapper. */
    return get_comments($args);
  }

  /**
   * @param string $email
   * @return false|string
   */
  public function isEmail(string $email) {
    return is_email($email);
  }

  /**
   * @param 'ARRAY_A'|'ARRAY_N'|'OBJECT' $output
   * @return WP_Comment|array|null
   */
  public function getComment(int $id, string $output = OBJECT) {
    return get_comment($id, $output);
  }

  /**
   * @param array<string, mixed>|string $args
   * @return WP_Term[]|int[]|string[]|string|WP_Error
   */
  public function getTerms($args = []) {
    /* @phpstan-ignore-next-line argument.type -- thin pass-through; WP stub declares a closed array shape that we do not enforce in this wrapper. */
    return get_terms($args);
  }

  /**
   * @param string|int $idOrEmail
   * @param array $args
   * @return false|string
   */
  public function getAvatarUrl($idOrEmail, $args = null) {
    return get_avatar_url($idOrEmail, $args);
  }

  /**
   * @param string $optionName
   * @param mixed $default
   * @return false|mixed|void
   */
  public function getOption(string $optionName, $default = false) {
    return get_option($optionName, $default);
  }

  /**
   * @param mixed $value
   */
  public function setTransient(string $transient, $value, int $expiration = 0): bool {
    return set_transient($transient, $value, $expiration);
  }

  /**
   * @return mixed
   */
  public function getTransient(string $transient) {
    return get_transient($transient);
  }

  public function deleteTransient(string $transient): bool {
    return delete_transient($transient);
  }

  /**
   * @param mixed $data
   */
  public function wpCacheAdd(string $key, $data, string $group = '', int $expire = 0): bool {
    // phpcs:ignore WordPressVIPMinimum.Performance.LowExpiryCacheTime.CacheTimeUndetermined -- Thin wrapper passes the caller-provided TTL.
    return wp_cache_add($key, $data, $group, $expire);
  }

  public function wpCacheDelete(string $key, string $group = ''): bool {
    return wp_cache_delete($key, $group);
  }

  /**
   * @param int|\WP_Post $post
   * @param bool $leavename
   * @return string|false
   */
  public function getPermalink($post, bool $leavename = false) {
    return get_permalink($post, $leavename);
  }

  /**
   * @return string[]
   */
  public function getCommentStatuses(): array {
    return get_comment_statuses();
  }

  public function getEditableRoles(): array {
    return get_editable_roles();
  }

  public function isRole(string $role): bool {
    return wp_roles()->is_role($role);
  }

  public function getPostStatuses(): array {
    return get_post_statuses();
  }

  /**
   * @return array<int,int|string|WP_Term>|string|WP_Error
   */
  public function wpGetPostTerms(int $postId, string $taxonomy, array $args = []) {
    return wp_get_post_terms($postId, $taxonomy, $args);
  }

  /**
   * @param int|\WP_Comment $comment
   * @return false|string
   */
  public function wpGetCommentStatus($comment) {
    return wp_get_comment_status($comment);
  }

  /**
   * @param 'names'|'objects' $output
   * @return string[]|\WP_Post_Type[]
   */
  public function getPostTypes(array $args = [], string $output = 'names', string $operator = 'and'): array {
    return get_post_types($args, $output, $operator);
  }

  public function postTypeSupports(string $type, string $feature): bool {
    return post_type_supports($type, $feature);
  }

  /**
   * @param 'names'|'objects' $output
   * @param 'and'|'or' $operator
   * @return string[]|\WP_Taxonomy[]
   */
  public function getTaxonomies(array $args = [], string $output = 'names', string $operator = 'and'): array {
    return get_taxonomies($args, $output, $operator);
  }

  /**
   * @return mixed
   */
  public function getCommentMeta(int $commentId, string $key = '', bool $isSingle = false) {
    return get_comment_meta($commentId, $key, $isSingle);
  }

  /**
   * @param int|WP_Term|object $term
   * @param string $taxonomy
   * @param 'ARRAY_A'|'ARRAY_N'|'OBJECT' $output
   * @param string $filter
   * @return WP_Term|array|WP_Error|null
   */
  public function getTerm($term, string $taxonomy = '', string $output = OBJECT, string $filter = 'raw') {
    return get_term($term, $taxonomy, $output, $filter);
  }

  /** @return \WP_Taxonomy|false */
  public function getTaxonomy(string $name) {
    return get_taxonomy($name);
  }

  /** @return int|string */
  public function currentTime(string $type, bool $gmt = false) {
    return current_time($type, $gmt);
  }

  /**
   * @param string $field
   * @param string|int $value
   * @return false|WP_User
   */
  public function getUserBy(string $field, $value) {
    return get_user_by($field, $value);
  }

  public function humanTimeDiff(int $from, int $to = 0): string {
    return human_time_diff($from, $to);
  }

  public function sanitizeFileName(string $filename): string {
    return sanitize_file_name($filename);
  }
}