<?php
/**
 * Shared feedback helper tests.
 *
 * @package GravityOps\Core
 */

namespace GOSP\GravityOps\Core\Tests\Unit;

use GOSP\GravityOps\Core\SuiteCore\Admin\ReviewPrompter;
use GOSP\GravityOps\Core\SuiteCore\Admin\SurveyPrompter;
use GOSP\GravityOps\Core\SuiteCore\SuiteCore;
use PHPUnit\Framework\TestCase;
use TestJsonResponse;

/**
 * Covers shared review and survey prompt lifecycle boundaries.
 */
final class FeedbackPrompterTest extends TestCase {
	/**
	 * Resets WordPress test state.
	 *
	 * @return void
	 */
	protected function setUp(): void {
		$_GET                               = [];
		$_POST                              = [];
		$_COOKIE                            = [];
		$GLOBALS['_test_actions']           = [];
		$GLOBALS['_test_caps']              = [];
		$GLOBALS['_test_options']           = [];
		$GLOBALS['_test_scheduled']         = [];
		$GLOBALS['_test_cleared_schedules'] = [];
		$GLOBALS['_test_remote_posts']      = [];
		$GLOBALS['_test_remote_response']   = [
			'response' => [ 'code' => 200 ],
			'body'     => '{}',
		];
	}

	/**
	 * Clears request state.
	 *
	 * @return void
	 */
	protected function tearDown(): void {
		$_GET    = [];
		$_POST   = [];
		$_COOKIE = [];
	}

	/**
	 * Ensures review display and actions require the configured capability.
	 *
	 * @return void
	 */
	public function test_review_prompt_enforces_capability_and_uses_inclusive_threshold(): void {
		$prompter = new ReviewPrompter( 'test_', 'Test', 'https://example.test/review' );
		$_POST    = [
			'test_rating_action' => 'done',
			'test_rating_nonce'  => wp_create_nonce( 'test_rating_asked' ),
		];

		$prompter->init();
		$prompter->maybe_show_review_request( 20, 20 );
		$this->assertFalse( get_option( 'test_rating_asked' ) );
		$this->assertArrayNotHasKey( 'admin_notices', $GLOBALS['_test_actions'] );

		$_POST                 = [];
		$GLOBALS['_test_caps'] = [ 'gform_full_access' ];
		$prompter->maybe_show_review_request( 20, 20 );
		$this->assertArrayHasKey( 'admin_notices', $GLOBALS['_test_actions'] );
	}

	/**
	 * Ensures a dismissed review notice is persisted as not interested.
	 *
	 * @return void
	 */
	public function test_review_dismissal_persists_not_interested(): void {
		$GLOBALS['_test_caps'] = [ 'gform_full_access' ];
		$_POST                 = [
			'prefix' => 'test_',
			'nonce'  => wp_create_nonce( 'gops_dismiss_review_test_' ),
		];

		try {
			ReviewPrompter::ajax_dismiss();
			$this->fail( 'Expected a JSON response.' );
		} catch ( TestJsonResponse $response ) {
			$this->assertTrue( $response->success );
		}

		$this->assertTrue( get_option( 'test_rating_asked' ) );
	}

	/**
	 * Ensures terminal legacy state becomes global and all plugin state is removed.
	 *
	 * @return void
	 */
	public function test_legacy_state_migrates_globally_and_cleans_plugin_data(): void {
		$GLOBALS['_test_options']['go_f4g_survey_status'] = [
			'state'  => 'completed',
			'due_at' => 0,
		];
		$GLOBALS['_test_options']['gosp_survey_status']   = [
			'state'  => 'ready',
			'due_at' => 0,
		];
		$GLOBALS['_test_scheduled']['gosp_survey']        = time() + 600;

		$this->survey()->init();

		$this->assertSame( 'completed', get_option( 'gravityops_survey_status' )['state'] );
		$this->assertTrue( get_option( 'gravityops_survey_status' )['legacy_cleaned'] );
		$this->assertFalse( get_option( 'go_f4g_survey_status' ) );
		$this->assertFalse( get_option( 'gosp_survey_status' ) );
		$this->assertContains( 'gosp_survey', $GLOBALS['_test_cleared_schedules'] );
	}

	/**
	 * Ensures a new global survey waits five days and then becomes ready.
	 *
	 * @return void
	 */
	public function test_global_survey_is_scheduled_once_and_advances_when_due(): void {
		$this->survey()->init();
		$status = get_option( 'gravityops_survey_status' );
		$this->assertSame( 'scheduled', $status['state'] );
		$this->assertGreaterThanOrEqual( time() + ( 5 * DAY_IN_SECONDS ) - 1, $status['due_at'] );

		$GLOBALS['_test_options']['gravityops_survey_status'] = [
			'state'          => 'scheduled',
			'due_at'         => time() - 1,
			'legacy_cleaned' => true,
		];
		$this->survey()->init();
		$this->assertSame( 'ready', get_option( 'gravityops_survey_status' )['state'] );
	}

	/**
	 * Ensures asynchronous decline and reminder actions persist distinct states.
	 *
	 * @param string $action Submitted action.
	 * @param string $state  Expected lifecycle state.
	 *
	 * @dataProvider actions
	 *
	 * @return void
	 */
	public function test_ajax_actions_persist_lifecycle_state( string $action, string $state ): void {
		$GLOBALS['_test_caps']                                = [ 'gform_full_access' ];
		$GLOBALS['_test_options']['gravityops_survey_status'] = [
			'state'          => 'ready',
			'due_at'         => 0,
			'legacy_cleaned' => true,
		];
		$_POST = [
			'survey_action' => $action,
			'nonce'         => wp_create_nonce( 'gops_survey' ),
		];

		try {
			$this->survey()->ajax_handle_action();
			$this->fail( 'Expected a JSON response.' );
		} catch ( TestJsonResponse $response ) {
			$this->assertTrue( $response->success );
		}

		$this->assertSame( $state, get_option( 'gravityops_survey_status' )['state'] );
		if ( 'done' === $action ) {
			$body = $GLOBALS['_test_remote_posts'][0][1]['body'];
			$this->assertSame( 'Test Plugin', $body['input_3'] );
			$this->assertSame( 'Test Plugin: premium', $body['input_4'] );
			$this->assertSame( 'Test Plugin: 1.0.0', $body['input_5'] );
		}
	}

	/**
	 * Provides survey action and lifecycle state pairs.
	 *
	 * @return array<string,array<int,string>>
	 */
	public function actions(): array {
		return [
			'skip'         => [ 'skip', 'skipped' ],
			'remind later' => [ 'remind', 'remind_later' ],
			'complete'     => [ 'done', 'completed' ],
		];
	}

	/**
	 * Creates a survey helper for tests.
	 *
	 * @return SurveyPrompter
	 */
	private function survey(): SurveyPrompter {
		return new SurveyPrompter( SuiteCore::instance() );
	}
}
