<?php
/**
 * bw-access phase-3: the Site Access SAVE HANDLER itself — grant, then revoke.
 *
 * Exists because the revoke path had a one-way door: the handler guarded on
 * user_can('manage_options'), which becomes true the moment administration is
 * granted, so the grant could never be taken back. Capability tests alone
 * wouldn't have caught it — this drives the handler the way the form does.
 */

$pass = 0; $fail = 0;
function t( $label, $ok ) {
	global $pass, $fail;
	$ok ? $pass++ : $fail++;
	echo ( $ok ? 'PASS  ' : 'FAIL !' ) . " $label\n";
}

$login = 'bw_access_test_save';
$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-save@example.invalid',
		'role'       => 'bw_staff',
	) ) );
}
$uid = $user->ID;

// Act as an administrator, as the screen requires.
$admins = get_users( array( 'role' => 'administrator', 'number' => 1, 'fields' => 'ID' ) );
wp_set_current_user( $admins[0] );

/** Drive the save logic exactly as the form posts it. */
function submit_access( $uid, $sections = array(), $tools = array(), $admin = false ) {
	$form = array();
	foreach ( $sections as $s ) { $form['bw_sections'][ $s ] = '1'; }
	foreach ( $tools as $tl )   { $form['bw_tools'][ $tl ]   = '1'; }
	if ( $admin ) { $form['bw_admin'] = '1'; }
	return bw_access_apply_submission( $uid, $form );
}

function caps_of( $uid ) {
	$u = get_userdata( $uid );
	return is_array( $u->caps ) ? $u->caps : array();
}

// ── grant ──────────────────────────────────────────────────────────────────
submit_access( $uid, array( 'bw_career' ), array( 'lead_ai' ), true );
$caps = caps_of( $uid );
t( 'G1 careers section granted', ! empty( $caps['edit_bw_careers'] ) && ! empty( $caps['publish_bw_careers'] ) );
t( 'G2 lead AI marker granted', ! empty( $caps['bw_view_lead_ai'] ) );
t( 'G3 administration granted', ! empty( $caps['manage_options'] ) && ! empty( $caps['activate_plugins'] ) );
t( 'G4 forms NOT granted (unticked)', empty( $caps['gravityforms_view_entries'] ) );
t( 'G5 pages NOT granted (unticked)', empty( $caps['edit_pages'] ) );

// ── revoke: the one-way-door check ─────────────────────────────────────────
submit_access( $uid, array(), array(), false );
$caps = caps_of( $uid );
t( 'R1 administration REVOKED', empty( $caps['manage_options'] ) && empty( $caps['activate_plugins'] ) );
t( 'R2 careers section revoked', empty( $caps['edit_bw_careers'] ) );
t( 'R3 lead AI revoked', empty( $caps['bw_view_lead_ai'] ) );
t( 'R4 nothing stray left behind', empty( array_diff( array_keys( $caps ), array( 'bw_staff' ) ) ) );

// ── partial change keeps the rest ──────────────────────────────────────────
submit_access( $uid, array( 'bw_career', 'course' ), array( 'forms' ), false );
$caps = caps_of( $uid );
t( 'P1 two sections + forms granted', ! empty( $caps['edit_bw_careers'] ) && ! empty( $caps['edit_bw_courses'] ) && ! empty( $caps['gravityforms_view_entries'] ) );
submit_access( $uid, array( 'bw_career' ), array( 'forms' ), false );
$caps = caps_of( $uid );
t( 'P2 dropping ONE section leaves the others', ! empty( $caps['edit_bw_careers'] ) && empty( $caps['edit_bw_courses'] ) && ! empty( $caps['gravityforms_view_entries'] ) );

// ── an Editor's role-given access is never stripped by a save ──────────────
$editors = get_users( array( 'role' => 'editor', 'number' => 1, 'fields' => 'ID' ) );
if ( $editors ) {
	$eid = $editors[0];
	$before = caps_of( $eid );
	submit_access( $eid, array(), array(), false );  // everything unticked
	$after = caps_of( $eid );
	t( 'E1 editor keeps role-given careers access', user_can( $eid, 'edit_bw_careers' ) );
	t( 'E2 editor keeps role-given Gravity Forms access', user_can( $eid, 'gravityforms_view_entries' ) );
	t( 'E3 editor individual caps untouched', $before == $after );
}

// ── a real Administrator is refused outright ───────────────────────────────
$before = caps_of( $admins[0] );
submit_access( $admins[0], array( 'page' ), array(), false );
t( 'A1 administrator record untouched by the handler', $before == caps_of( $admins[0] ) );

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