<?php

declare(strict_types=1);

namespace SiteFort\Includes;

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

/**
 * Central capability resolver for SiteFort control-plane access.
 *
 * On multisite, SiteFort manages shared network resources such as
 * wp-config.php, root firewall files, and common codebase state. Those
 * operations must be limited to network administrators.
 */
final class Capabilities {

	/**
	 * WordPress-managed files that live at the install root and should be
	 * treated as core-owned assets for file-mutation capability checks.
	 */
	private const KNOWN_ROOT_CORE_FILES = [
		'index.php',
		'license.txt',
		'readme.html',
		'wp-activate.php',
		'wp-blog-header.php',
		'wp-comments-post.php',
		'wp-config-sample.php',
		'wp-config.php',
		'wp-cron.php',
		'wp-links-opml.php',
		'wp-load.php',
		'wp-login.php',
		'wp-mail.php',
		'wp-settings.php',
		'wp-signup.php',
		'wp-trackback.php',
		'xmlrpc.php',
	];

	/**
	 * Capability required to manage SiteFort's admin/control plane.
	 */
	public static function admin_capability(): string {
		return is_multisite() ? 'manage_network_options' : 'manage_options';
	}

	/**
	 * Whether the current user can manage SiteFort.
	 */
	public static function can_manage_plugin(): bool {
		return function_exists( 'current_user_can' ) && current_user_can( self::admin_capability() );
	}

	/**
	 * Whether the given user object can manage SiteFort.
	 */
	public static function user_can_manage_plugin( \WP_User $user ): bool {
		return function_exists( 'user_can' ) && user_can( $user, self::admin_capability() );
	}

	/**
	 * Whether the current user can edit the given WordPress user account.
	 */
	public static function can_edit_user_account( int $user_id ): bool {
		return $user_id > 0
			&& function_exists( 'current_user_can' )
			&& current_user_can( 'edit_user', $user_id );
	}

	/**
	 * Whether the current user can delete the given WordPress user account.
	 *
	 * Mirrors WordPress core's stronger user-deletion boundary instead of
	 * assuming plugin-management access implies user-administration rights.
	 */
	public static function can_delete_user_account( int $user_id ): bool {
		if ( $user_id <= 0 || ! function_exists( 'current_user_can' ) ) {
			return false;
		}

		if ( is_multisite() && ! current_user_can( 'manage_network_users' ) ) {
			return false;
		}

		return current_user_can( 'delete_users' )
			&& current_user_can( 'delete_user', $user_id );
	}

	/**
	 * Registered user roles (including custom roles) for role-scoping controls.
	 *
	 * @return array<int,array{value:string,label:string}>
	 */
	public static function get_selectable_roles(): array {
		if ( ! function_exists( 'wp_roles' ) ) {
			return [];
		}

		$all = wp_roles()->roles;
		$all = is_array( $all ) ? $all : [];

		// phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedHooknameFound -- WordPress core filter for assignable roles.
		$all = apply_filters( 'editable_roles', $all );

		$list = [];
		foreach ( $all as $slug => $details ) {
			$slug = sanitize_key( (string) $slug );
			if ( $slug === '' ) {
				continue;
			}
			$name   = is_array( $details ) && isset( $details['name'] ) ? (string) $details['name'] : $slug;
			$list[] = [
				'value' => $slug,
				'label' => translate_user_role( $name ),
			];
		}

		return $list;
	}

	/**
	 * Infer the owning WordPress component for a scanner file path.
	 */
	public static function infer_scanner_file_component_type( string $file_path, string $preferred_component_type = '' ): string {
		$preferred_component_type = sanitize_key( $preferred_component_type );
		if ( in_array( $preferred_component_type, [ 'core', 'plugin', 'theme', 'uploads' ], true ) ) {
			return $preferred_component_type;
		}

		$normalized = self::normalize_scanner_relative_path( $file_path );
		if ( $normalized === '' ) {
			return 'unknown';
		}

		if ( str_contains( $normalized, '/plugins/' ) || strpos( $normalized, 'wp-content/plugins/' ) === 0 ) {
			return 'plugin';
		}

		if ( str_contains( $normalized, '/themes/' ) || strpos( $normalized, 'wp-content/themes/' ) === 0 ) {
			return 'theme';
		}

		if ( str_contains( $normalized, '/uploads/' ) || strpos( $normalized, 'wp-content/uploads/' ) === 0 ) {
			return 'uploads';
		}

		if (
			strpos( $normalized, 'wp-admin/' ) === 0
			|| strpos( $normalized, 'wp-includes/' ) === 0
			|| in_array( $normalized, self::KNOWN_ROOT_CORE_FILES, true )
		) {
			return 'core';
		}

		return 'unknown';
	}

	/**
	 * Whether the current user can mutate a scanner-managed file path.
	 *
	 * Plugin/theme/core files require the matching native WordPress update
	 * capability so SiteFort control-plane access cannot be used to bypass
	 * core code-management boundaries.
	 */
	public static function can_modify_scanner_file( string $file_path, string $preferred_component_type = '' ): bool {
		if ( ! self::can_manage_plugin() ) {
			return false;
		}

		$component_type = self::infer_scanner_file_component_type( $file_path, $preferred_component_type );
		$capability = self::managed_code_component_capability( $component_type );
		if ( $capability === null ) {
			return true;
		}

		return function_exists( 'current_user_can' ) && current_user_can( $capability );
	}

	/**
	 * @return string|null
	 */
	private static function managed_code_component_capability( string $component_type ): ?string {
		$component_type = sanitize_key( $component_type );

		switch ( $component_type ) {
			case 'plugin':
				return 'update_plugins';
			case 'theme':
				return 'update_themes';
			case 'core':
				return 'update_core';
			default:
				return null;
		}
	}

	private static function normalize_scanner_relative_path( string $file_path ): string {
		$normalized = ltrim( strtolower( wp_normalize_path( $file_path ) ), '/' );
		$root = ltrim( strtolower( wp_normalize_path( trailingslashit( ABSPATH ) ) ), '/' );

		if ( $root !== '' && strpos( $normalized, $root ) === 0 ) {
			$normalized = ltrim( substr( $normalized, strlen( $root ) ), '/' );
		}

		return $normalized;
	}
}
