<?php
/**
 * Shield permissions helper.
 *
 * @package Polanger_Shield
 */

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

class Polanger_Shield_Permissions {

  /**
   * Determine if the current user can manage Shield.
   *
   * @param bool $allow_unconfigured If true, protected admin may pass even when not configured.
   * @return bool
   */
  public static function current_user_can_manage_shield( $allow_unconfigured = false ) {
    $user_id = get_current_user_id();
    if ( ! $user_id ) {
      return false;
    }

    if ( ! current_user_can( 'manage_options' ) ) {
      return false;
    }

    if ( function_exists( 'pdt_get_user_access_level' ) && 'full' !== pdt_get_user_access_level( $user_id ) ) {
      return false;
    }

    $settings = Polanger_Shield_Settings::instance()->get_settings();
    $manager_user_ids = self::normalize_user_ids( isset( $settings['manager_user_ids'] ) ? $settings['manager_user_ids'] : array() );
    $protected_admin_id = self::get_protected_admin_id();

    if ( empty( $manager_user_ids ) ) {
      return $allow_unconfigured ? ( $protected_admin_id === $user_id ) : false;
    }

    if ( $protected_admin_id === $user_id ) {
      return true;
    }

    return in_array( $user_id, $manager_user_ids, true );
  }

  /**
   * Check whether a user is targeted by a rule.
   *
   * @param object $rule Rule record.
   * @param int    $user_id User ID.
   * @return bool
   */
  public static function is_user_targeted_by_rule( $rule, $user_id ) {
    if ( ! $rule || ! isset( $rule->target_user_ids ) ) {
      return false;
    }

    $targets = json_decode( (string) $rule->target_user_ids, true );
    if ( ! is_array( $targets ) ) {
      $targets = array();
    }

    $targets = self::normalize_user_ids( $targets );
    return in_array( absint( $user_id ), $targets, true );
  }

  /**
   * Check note visibility for current user.
   *
   * @param object $rule Rule record.
   * @param int    $user_id User ID.
   * @return bool
   */
  public static function can_user_see_note( $rule, $user_id ) {
    if ( ! $rule || ! isset( $rule->note_visible_user_ids ) ) {
      return false;
    }

    $visible = json_decode( (string) $rule->note_visible_user_ids, true );
    if ( ! is_array( $visible ) ) {
      $visible = array();
    }

    $visible = self::normalize_user_ids( $visible );
    return in_array( absint( $user_id ), $visible, true );
  }

  /**
   * Resolve fallback protected admin ID.
   *
   * @return int
   */
  public static function get_protected_admin_id() {
    if ( is_multisite() ) {
      $super_admins = get_super_admins();
      if ( ! empty( $super_admins ) ) {
        $super_admin = get_user_by( 'login', $super_admins[0] );
        if ( $super_admin ) {
          return (int) $super_admin->ID;
        }
      }
    }

    $admins = get_users(
      array(
        'role'    => 'administrator',
        'orderby' => 'ID',
        'order'   => 'ASC',
        'number'  => 1,
        'fields'  => 'ids',
      )
    );

    if ( ! empty( $admins ) ) {
      $admin_id = self::normalize_user_id( $admins[0] );
      if ( $admin_id ) {
        return $admin_id;
      }
    }

    return (int) get_current_user_id();
  }

  /**
   * Normalize a mixed user value into a user ID.
   *
   * @param mixed $user User ID, WP_User, stdClass, or array-like value.
   * @return int
   */
  public static function normalize_user_id( $user ) {
    if ( is_numeric( $user ) ) {
      return absint( $user );
    }

    if ( $user instanceof WP_User ) {
      return absint( $user->ID );
    }

    if ( is_object( $user ) ) {
      foreach ( array( 'ID', 'id', 'user_id' ) as $property ) {
        if ( isset( $user->{$property} ) && is_numeric( $user->{$property} ) ) {
          return absint( $user->{$property} );
        }
      }
    }

    if ( is_array( $user ) ) {
      foreach ( array( 'ID', 'id', 'user_id' ) as $key ) {
        if ( isset( $user[ $key ] ) && is_numeric( $user[ $key ] ) ) {
          return absint( $user[ $key ] );
        }
      }
    }

    return 0;
  }

  /**
   * Normalize a mixed list into unique user IDs.
   *
   * @param mixed $users User list.
   * @return array
   */
  public static function normalize_user_ids( $users ) {
    $ids = array();

    foreach ( (array) $users as $user ) {
      $user_id = self::normalize_user_id( $user );
      if ( $user_id ) {
        $ids[] = $user_id;
      }
    }

    return array_values( array_unique( $ids ) );
  }
}
