<?php
/**
 * bw-access phase-2 matrix: tools (Forms, Lead AI), site administration,
 * guides-for-everyone, and the capability-borrow boundaries.
 *
 * Uses its OWN throwaway user so it can't be skewed by demo grants left on the
 * phase-1 fixture, and refreshes the current user after every capability change
 * (wp_set_current_user returns early when the id is unchanged, so re-setting the
 * same id does NOT pick up new capabilities).
 */

$pass = 0; $fail = 0;
function t( $label, $ok ) {
	global $pass, $fail;
	$ok ? $pass++ : $fail++;
	echo ( $ok ? 'PASS  ' : 'FAIL !' ) . " $label\n";
}
function refresh( $uid ) {
	wp_set_current_user( 0 );
	wp_set_current_user( $uid );
}
function screen( $page ) {
	if ( null === $page ) { unset( $_GET['page'] ); } else { $_GET['page'] = $page; }
}

if ( ! defined( 'WP_ADMIN' ) ) { define( 'WP_ADMIN', true ); }

$login = 'bw_access_test_tools';
$user  = get_user_by( 'login', $login );
if ( ! $user ) {
	$user = get_userdata( wp_insert_user( array(
		'user_login' => $login,
		'user_pass'  => wp_generate_password( 32 ),
		'user_email' => 'bw-access-tools@example.invalid',
		'role'       => 'bw_staff',
	) ) );
}
$uid = $user->ID;
echo "fixture: clean bw_staff user #$uid\n\n";

// ── A. guides: readable by a plain teacher, on the guides screen only ──────
refresh( $uid );
screen( null );
t( 'A1 no edit_posts on a normal screen', ! current_user_can( 'edit_posts' ) );
screen( 'bw-guides' );
t( 'A2 edit_posts borrowed on the guides screen', current_user_can( 'edit_posts' ) );
t( 'A3 borrow does not extend to manage_options', ! current_user_can( 'manage_options' ) );
screen( 'bw-lead-ai' );
t( 'A4 no manage_options on Lead AI without the grant', ! current_user_can( 'manage_options' ) );
screen( 'edit.php' ); // not a `page` screen at all
t( 'A5 no edit_posts on the Posts list', ! current_user_can( 'edit_posts' ) );
screen( null );

// The guides AJAX endpoints WRITE (shared tags, notes, a full sync) — a reader
// must never borrow a capability there, or "everyone can read the guides"
// becomes "everyone can retag the guides".
$_REQUEST['action'] = 'bw_guides_save_tags';
add_filter( 'wp_doing_ajax', '__return_true' );
t( 'A6 no edit_posts for the guides SAVE endpoints', ! current_user_can( 'edit_posts' ) );
$_REQUEST['action'] = 'bw_guides_check_updates';
t( 'A7 no edit_posts for the guides sync endpoint', ! current_user_can( 'edit_posts' ) );
remove_filter( 'wp_doing_ajax', '__return_true' );
unset( $_REQUEST['action'] );

// ── B. staff lockout: still on, guides excepted ────────────────────────────
t( 'B1 ungranted teacher is profile-locked', bw_staff_is_profile_only( get_userdata( $uid ) ) );
screen( 'bw-guides' );
t( 'B2 guides screen is exempt from the wp-admin bounce', (bool) bw_access_current_proxy() );
screen( 'plugins.php' );
t( 'B3 a non-guides screen is NOT exempt', null === bw_access_current_proxy() );
screen( null );

// ── C. Lead AI grant ───────────────────────────────────────────────────────
$tools = bw_access_tools();
$u = get_userdata( $uid );
foreach ( $tools['lead_ai']['caps'] as $cap ) { $u->add_cap( $cap ); }
refresh( $uid );
screen( 'bw-lead-ai' );
t( 'C1 granted user borrows manage_options on the Lead AI screen', current_user_can( 'manage_options' ) );
screen( 'bw-lead-ai-journey' );
t( 'C2 …and on the journey viewer', current_user_can( 'manage_options' ) );
screen( null );
t( 'C3 …but not anywhere else', ! current_user_can( 'manage_options' ) );
screen( 'bw-site-access' );
t( 'C4 …not on other plugin screens', ! current_user_can( 'manage_options' ) );
screen( null );
t( 'C5 Lead AI grant gives no content access', ! current_user_can( 'edit_pages' ) && ! current_user_can( 'edit_bw_careers' ) );
t( 'C6 Lead AI grant lifts the teacher lockout', ! bw_staff_is_profile_only( get_userdata( $uid ) ) );

// ── D. Forms grant ─────────────────────────────────────────────────────────
$u = get_userdata( $uid );
foreach ( $tools['forms']['caps'] as $cap ) { $u->add_cap( $cap ); }
refresh( $uid );
t( 'D1 can view GF entries', current_user_can( 'gravityforms_view_entries' ) );
t( 'D2 can edit forms', current_user_can( 'gravityforms_edit_forms' ) );
t( 'D3 NOT GF global settings', ! current_user_can( 'gravityforms_edit_settings' ) );
t( 'D4 Forms grant gives no content access', ! current_user_can( 'edit_pages' ) );

// ── E. site administration ─────────────────────────────────────────────────
$u = get_userdata( $uid );
foreach ( bw_access_admin_caps() as $cap ) { $u->add_cap( $cap ); }
refresh( $uid );
t( 'E1 manage_options', current_user_can( 'manage_options' ) );
t( 'E2 activate_plugins', current_user_can( 'activate_plugins' ) );
t( 'E3 edit_theme_options', current_user_can( 'edit_theme_options' ) );
t( 'E4 Yoast settings', current_user_can( 'wpseo_manage_options' ) );
t( 'E5 NO content: pages', ! current_user_can( 'edit_pages' ) );
t( 'E6 NO content: posts', ! current_user_can( 'edit_posts' ) );
t( 'E7 NO content: careers', ! current_user_can( 'edit_bw_careers' ) );
t( 'E8 NOT the user roster', ! current_user_can( 'edit_users' ) && ! current_user_can( 'promote_users' ) );
t( 'E9 NOT the PHP file editors', ! current_user_can( 'edit_plugins' ) && ! current_user_can( 'edit_themes' ) );

// ── F. audit ───────────────────────────────────────────────────────────────
wp_set_current_user( 0 );
$labels = bw_access_section_grant_holders();
$mine   = isset( $labels[ $uid ] ) ? $labels[ $uid ] : array();
t( 'F1 audit lists Lead AI', in_array( 'Lead AI', $mine, true ) );
t( 'F2 audit lists Forms', (bool) preg_grep( '/Forms/', $mine ) );
t( 'F3 audit lists Site administration', in_array( 'Site administration', $mine, true ) );

// ── G. removal is clean ────────────────────────────────────────────────────
$u = get_userdata( $uid );
foreach ( array_merge( $tools['lead_ai']['caps'], $tools['forms']['caps'], bw_access_admin_caps() ) as $cap ) {
	$u->remove_cap( $cap );
}
refresh( $uid );
screen( 'bw-lead-ai' );
t( 'G1 revoked: no manage_options on the Lead AI screen', ! current_user_can( 'manage_options' ) );
screen( null );
t( 'G2 revoked: no GF entries', ! current_user_can( 'gravityforms_view_entries' ) );
t( 'G3 revoked: teacher is profile-locked again', bw_staff_is_profile_only( get_userdata( $uid ) ) );
screen( 'bw-guides' );
t( 'G4 revoked: guides still readable (never was a grant)', current_user_can( 'edit_posts' ) );
screen( null );
$labels = bw_access_section_grant_holders();
t( 'G5 revoked: gone from the audit table', ! isset( $labels[ $uid ] ) );

// ── H. regressions ─────────────────────────────────────────────────────────
$editor = get_users( array( 'role' => 'editor', 'number' => 1 ) );
if ( $editor ) {
	t( 'H1 editor still has real edit_posts', user_can( $editor[0], 'edit_posts' ) );
	t( 'H2 editor still barred from manage_options', ! user_can( $editor[0], 'manage_options' ) );
}
$admin = get_users( array( 'role' => 'administrator', 'number' => 1 ) );
if ( $admin ) {
	t( 'H3 admin unaffected', user_can( $admin[0], 'manage_options' ) && user_can( $admin[0], 'edit_pages' ) );
}

wp_delete_user( $uid );
echo "\ncleanup: throwaway user deleted\n";
echo "\nRESULT: $pass passed, $fail failed\n";
