<?php
/**
 * Spec for Scope_Gate (L4 enforcement).
 *
 * @package Ppok\AIToolkit\Tests
 * @license GPL-2.0-or-later
 */

namespace Ppok\AIToolkit\Tests;

use Ppok\AIToolkit\Abilities\Scope_Gate;

class Test_Scope_Gate extends \WP_UnitTestCase {

	protected function tearDown(): void {
		delete_option( Scope_Gate::OPTION_KEY );
		parent::tearDown();
	}

	public function test_defaults_to_post_only_and_draft_only_when_option_missing(): void {
		delete_option( Scope_Gate::OPTION_KEY );
		$this->assertSame( array( 'post' ), Scope_Gate::allowed_post_types() );
		$this->assertSame( array( 'draft' ), Scope_Gate::allowed_post_statuses() );
	}

	public function test_check_post_type_passes_when_in_allowlist(): void {
		update_option( Scope_Gate::OPTION_KEY, array( 'write_post_types' => array( 'post', 'page' ) ) );
		$this->assertTrue( Scope_Gate::check_post_type( 'post' ) );
		$this->assertTrue( Scope_Gate::check_post_type( 'page' ) );
	}

	public function test_check_post_type_rejects_outside_allowlist_with_structured_error(): void {
		update_option( Scope_Gate::OPTION_KEY, array( 'write_post_types' => array( 'post' ) ) );
		$result = Scope_Gate::check_post_type( 'page' );
		$this->assertInstanceOf( \WP_Error::class, $result );
		$this->assertSame( 'scope_blocked', $result->get_error_code() );
		$data = $result->get_error_data();
		$this->assertSame( 'write_post_types', $data['rejected_by'] );
		$this->assertSame( 'page', $data['value'] );
		$this->assertSame( array( 'post' ), $data['allowed_value'] );
	}

	public function test_check_post_status_passes_for_draft_default(): void {
		delete_option( Scope_Gate::OPTION_KEY );
		$this->assertTrue( Scope_Gate::check_post_status( 'draft' ) );
	}

	public function test_check_post_status_rejects_publish_without_explicit_opt_in(): void {
		delete_option( Scope_Gate::OPTION_KEY );
		$result = Scope_Gate::check_post_status( 'publish' );
		$this->assertInstanceOf( \WP_Error::class, $result );
		$data = $result->get_error_data();
		$this->assertSame( 'write_post_statuses', $data['rejected_by'] );
	}

	public function test_check_post_status_requires_edit_published_posts_cap_even_when_publish_is_allowed(): void {
		update_option( Scope_Gate::OPTION_KEY, array( 'write_post_statuses' => array( 'draft', 'publish' ) ) );

		// Author has edit_posts but NOT edit_published_posts.
		$author = self::factory()->user->create( array( 'role' => 'contributor' ) );
		wp_set_current_user( $author );

		$result = Scope_Gate::check_post_status( 'publish' );
		$this->assertInstanceOf( \WP_Error::class, $result );
		$data = $result->get_error_data();
		$this->assertSame( 'edit_published_posts', $data['rejected_by'] );
	}

	public function test_check_post_status_passes_publish_for_editor_when_opted_in(): void {
		update_option( Scope_Gate::OPTION_KEY, array( 'write_post_statuses' => array( 'draft', 'publish' ) ) );
		$editor = self::factory()->user->create( array( 'role' => 'editor' ) );
		wp_set_current_user( $editor );
		$this->assertTrue( Scope_Gate::check_post_status( 'publish' ) );
	}
}
