<?php
/**
 * bw-access test matrix. Temporary — deleted after the run.
 * Creates one throwaway bw_staff user, grants a real page, exercises the
 * capability pipeline + REST, then reverts every mutation it made.
 */

if ( ! defined( 'WP_ADMIN' ) ) {
	define( 'WP_ADMIN', true ); // lets the pre_get_posts admin-list test run headless.
}

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

// ── fixtures ────────────────────────────────────────────────────────────────
$login = 'bw_access_test_user';
$user  = get_user_by( 'login', $login );
if ( ! $user ) {
	$uid  = wp_insert_user( array(
		'user_login' => $login,
		'user_pass'  => wp_generate_password( 32 ),
		'user_email' => 'bw-access-test@example.invalid',
		'role'       => 'bw_staff',
	) );
	$user = get_userdata( $uid );
}
$uid = $user->ID;

$pages = get_posts( array( 'post_type' => 'page', 'post_status' => 'publish', 'numberposts' => 2, 'orderby' => 'ID', 'order' => 'DESC' ) );
list( $granted, $control ) = array( $pages[0], $pages[1] );
update_post_meta( $granted->ID, 'bw_editors', array( (string) $uid ) );
echo "fixtures: user #$uid, granted page #{$granted->ID}, control page #{$control->ID}\n\n";

// ── A. capability outcomes (per-page grant) ────────────────────────────────
wp_set_current_user( $uid );
t( 'A1 can edit granted page', current_user_can( 'edit_post', $granted->ID ) );
t( 'A2 canNOT edit control page', ! current_user_can( 'edit_post', $control->ID ) );
t( 'A3 canNOT delete granted page', ! current_user_can( 'delete_post', $granted->ID ) );
t( 'A4 dynamic edit_pages primitive', current_user_can( 'edit_pages' ) );
t( 'A5 no edit_posts (no blog grant)', ! current_user_can( 'edit_posts' ) );
t( 'A6 upload_files granted', current_user_can( 'upload_files' ) );
t( 'A7 no publish_pages outside a write to the granted page', ! current_user_can( 'publish_pages' ) );
t( 'A8 no careers access', ! current_user_can( 'edit_bw_careers' ) );

// ── B. REST (the real Gutenberg path) ───────────────────────────────────────
$old_title = $granted->post_title;
$req = new WP_REST_Request( 'PUT', '/wp/v2/pages/' . $granted->ID );
$req->set_body_params( array( 'title' => $old_title . ' [bw-test]', 'status' => 'publish' ) );
$res = rest_do_request( $req );
t( 'B1 REST update of granted PUBLISHED page incl. status=publish → 200', 200 === $res->get_status() );

$req = new WP_REST_Request( 'PUT', '/wp/v2/pages/' . $control->ID );
$req->set_body_params( array( 'title' => 'x' ) );
$res = rest_do_request( $req );
t( 'B2 REST update of control page → 403', 403 === $res->get_status() );

$req = new WP_REST_Request( 'POST', '/wp/v2/pages' );
$req->set_body_params( array( 'title' => 'bw-test should never exist' ) );
$res = rest_do_request( $req );
t( 'B3 REST create page → 403 (grant excludes creating)', 403 === $res->get_status() );

// revert the title edit from B1.
wp_set_current_user( 0 );
wp_update_post( array( 'ID' => $granted->ID, 'post_title' => $old_title ) );
wp_set_current_user( $uid );

// ── C. admin list narrowing ─────────────────────────────────────────────────
$GLOBALS['pagenow'] = 'edit.php';
$q = new WP_Query();
$GLOBALS['wp_the_query'] = $q;
$q->query( array( 'post_type' => 'page', 'posts_per_page' => -1, 'fields' => 'ids' ) );
$ids = array_map( 'intval', $q->posts );
t( 'C1 grant-only user sees ONLY the granted page in the list', array( $granted->ID ) === $ids );

// ── D. section grant: full Careers access ──────────────────────────────────
wp_set_current_user( 0 );
$u = get_userdata( $uid );
foreach ( bw_access_family_caps( 'bw_careers' ) as $cap ) { $u->add_cap( $cap ); }
wp_set_current_user( $uid ); // fresh allcaps
$user_reloaded = wp_get_current_user();

t( 'D1 can edit careers now', current_user_can( 'edit_bw_careers' ) );
$career_base = get_post_type_object( 'bw_career' )->rest_base ?: 'bw_career';
$req = new WP_REST_Request( 'POST', '/wp/v2/' . $career_base );
$req->set_body_params( array( 'title' => 'bw-test posting', 'status' => 'draft' ) );
$res = rest_do_request( $req );
$career_id = 201 === $res->get_status() ? $res->get_data()['id'] : 0;
t( 'D2 REST create career draft → 201', 201 === $res->get_status() );

if ( $career_id ) {
	$req = new WP_REST_Request( 'PUT', '/wp/v2/' . $career_base . '/' . $career_id );
	$req->set_body_params( array( 'status' => 'publish' ) );
	$res = rest_do_request( $req );
	t( 'D3 REST publish career → 200', 200 === $res->get_status() );

	$req = new WP_REST_Request( 'DELETE', '/wp/v2/' . $career_base . '/' . $career_id );
	$res = rest_do_request( $req );
	t( 'D4 REST trash career → 200', 200 === $res->get_status() );
}
t( 'D5 still cannot edit control PAGE', ! current_user_can( 'edit_post', $control->ID ) );
t( 'D6 cannot edit courses (different section)', ! current_user_can( 'edit_bw_courses' ) );

// ── E. staff-access integration + helpers ──────────────────────────────────
t( 'E1 granted teacher is NOT profile-locked', ! bw_staff_is_profile_only( get_userdata( $uid ) ) );
$pure = get_users( array( 'role' => 'bw_staff', 'exclude' => array( $uid ), 'number' => 1 ) );
if ( $pure ) {
	t( 'E2 an ungranted teacher IS still profile-locked', bw_staff_is_profile_only( $pure[0] ) );
}
t( 'E3 any-grant helper true', bw_access_user_has_any_grant( $uid ) );
$holders = bw_access_section_grant_holders();
t( 'E4 audit: section holders includes test user (Careers)', isset( $holders[ $uid ] ) && in_array( 'Careers', $holders[ $uid ], true ) );
$pgrants = bw_access_all_page_grants();
t( 'E5 audit: page grants includes test user → granted page', isset( $pgrants[ $uid ] ) && in_array( $granted->ID, $pgrants[ $uid ], true ) );

// ── F. regressions ──────────────────────────────────────────────────────────
wp_set_current_user( 0 );
$editor = get_users( array( 'role' => 'editor', 'number' => 1 ) );
if ( $editor ) {
	t( 'F1 editor still edits any page', user_can( $editor[0], 'edit_post', $control->ID ) );
	t( 'F2 editor still edits careers', user_can( $editor[0], 'edit_bw_careers' ) );
	t( 'F3 editor untouched by list narrowing', ! bw_access_grant_only( $editor[0], 'page' ) );
}
$admin = get_users( array( 'role' => 'administrator', 'number' => 1 ) );
if ( $admin ) {
	t( 'F4 admin edits everything', user_can( $admin[0], 'edit_post', $granted->ID ) && user_can( $admin[0], 'edit_bw_hundreds' ) );
}

// ── cleanup ─────────────────────────────────────────────────────────────────
delete_post_meta( $granted->ID, 'bw_editors' );
$u = get_userdata( $uid );
foreach ( bw_access_family_caps( 'bw_careers' ) as $cap ) { $u->remove_cap( $cap ); }
if ( $career_id ) {
	wp_delete_post( $career_id, true );
}
echo "\ncleanup: meta deleted, career caps removed, test career hard-deleted (test user kept for a browser check)\n";
echo "\nRESULT: $pass passed, $fail failed\n";
