<?php
/**
 * Team Survey — admin pages.
 *
 * Three hidden submenu pages reachable from the main AI Schema Pro
 * options page (and via direct URL):
 *
 *   - bw-ai-schema-surveys          Queue
 *   - bw-ai-schema-survey-detail    Per-submission triage / schema review / publish
 *   - bw-ai-schema-survey-settings  Open/renew window, URL, notifications, capability
 *
 * All gated on BW_Schema_Survey::CAP. State-changing handlers all
 * nonce-checked. See docs/SPEC-team-survey.md § Admin.
 *
 * @package BW_AI_Schema_Pro
 * @since 2.2.0
 */

if ( ! defined( 'ABSPATH' ) ) {
	exit;
}

class BW_Schema_Survey_Admin {

	const PAGE_QUEUE    = 'bw-ai-schema-surveys';
	const PAGE_DETAIL   = 'bw-ai-schema-survey-detail';
	const PAGE_ADD      = 'bw-ai-schema-survey-add';
	const PAGE_SETTINGS = 'bw-ai-schema-survey-settings';

	const NONCE_QUEUE    = 'bw_schema_survey_queue';
	const NONCE_TRIAGE   = 'bw_schema_survey_triage';
	const NONCE_REVIEW   = 'bw_schema_survey_review';
	const NONCE_PUBLISH  = 'bw_schema_survey_publish';
	const NONCE_SETTINGS = 'bw_schema_survey_settings';
	const NONCE_ADD      = 'bw_schema_survey_add';
	const NONCE_SETUP    = 'bw_schema_survey_setup';

	public static function init() {
		add_action( 'admin_menu', array( __CLASS__, 'register_pages' ), 20 );
	}

	public static function register_pages() {
		add_submenu_page(
			null,
			__( 'Team Surveys', 'bw-ai-schema-pro' ),
			__( 'Team Surveys', 'bw-ai-schema-pro' ),
			BW_Schema_Survey::CAP,
			self::PAGE_QUEUE,
			array( __CLASS__, 'render_queue_page' )
		);
		add_submenu_page(
			null,
			__( 'Survey detail', 'bw-ai-schema-pro' ),
			__( 'Survey detail', 'bw-ai-schema-pro' ),
			BW_Schema_Survey::CAP,
			self::PAGE_DETAIL,
			array( __CLASS__, 'render_detail_page' )
		);
		add_submenu_page(
			null,
			__( 'Team Survey settings', 'bw-ai-schema-pro' ),
			__( 'Team Survey settings', 'bw-ai-schema-pro' ),
			BW_Schema_Survey::CAP,
			self::PAGE_SETTINGS,
			array( __CLASS__, 'render_settings_page' )
		);
		add_submenu_page(
			null,
			__( 'Add team info', 'bw-ai-schema-pro' ),
			__( 'Add team info', 'bw-ai-schema-pro' ),
			BW_Schema_Survey::CAP,
			self::PAGE_ADD,
			array( __CLASS__, 'render_add_page' )
		);
	}

	/* ---------------- Queue ---------------- */

	public static function render_queue_page() {
		if ( ! current_user_can( BW_Schema_Survey::CAP ) ) {
			wp_die( esc_html__( 'You do not have permission to view this page.', 'bw-ai-schema-pro' ) );
		}

		self::maybe_handle_setup();
		self::maybe_handle_bulk();

		if ( ! BW_Schema_Survey::is_setup_complete() ) {
			$suggestions = BW_Schema_Survey::suggest_team_post_types();
			$all_options = BW_Schema_Survey::all_eligible_post_types();
			$nonce       = wp_create_nonce( self::NONCE_SETUP );
			include BW_SCHEMA_PLUGIN_DIR . 'admin/views/survey-missing-team-cpt.php';
			return;
		}

		$status_filter = isset( $_GET['status'] ) ? sanitize_key( wp_unslash( $_GET['status'] ) ) : '';
		$holding_only  = ! empty( $_GET['holding'] );
		$search        = isset( $_GET['s'] ) ? sanitize_text_field( wp_unslash( $_GET['s'] ) ) : '';
		$page          = isset( $_GET['paged'] ) ? max( 1, absint( $_GET['paged'] ) ) : 1;

		$query_args = array(
			'status'   => $status_filter,
			'search'   => $search,
			'per_page' => 50,
			'page'     => $page,
		);
		if ( $holding_only ) {
			$query_args['target_post_id'] = '__holding__';
		}

		$responses    = BW_Schema_Survey_Store::query( $query_args );
		$status_counts = self::status_counts();
		$nonce        = wp_create_nonce( self::NONCE_QUEUE );
		$base_url     = admin_url( 'options-general.php?page=' . self::PAGE_QUEUE );

		include BW_SCHEMA_PLUGIN_DIR . 'admin/views/survey-queue.php';
	}

	private static function status_counts() {
		$counts = array();
		foreach ( BW_Schema_Survey_Store::valid_statuses() as $s ) {
			$counts[ $s ] = BW_Schema_Survey_Store::count_by_status( $s );
		}
		$counts['all'] = BW_Schema_Survey_Store::count_by_status( 'all' );
		return $counts;
	}

	private static function maybe_handle_bulk() {
		if ( empty( $_POST['bw_schema_survey_queue_action'] ) ) {
			return;
		}
		if ( ! current_user_can( BW_Schema_Survey::CAP ) ) {
			wp_die( esc_html__( 'Permission denied.', 'bw-ai-schema-pro' ) );
		}
		$nonce = isset( $_POST['_bw_schema_survey_queue_nonce'] ) ? (string) wp_unslash( $_POST['_bw_schema_survey_queue_nonce'] ) : '';
		if ( ! wp_verify_nonce( $nonce, self::NONCE_QUEUE ) ) {
			wp_die( esc_html__( 'Security check failed.', 'bw-ai-schema-pro' ) );
		}

		$action = sanitize_key( wp_unslash( $_POST['bw_schema_survey_queue_action'] ) );
		$ids    = isset( $_POST['ids'] ) && is_array( $_POST['ids'] )
			? array_map( 'absint', wp_unslash( $_POST['ids'] ) )
			: array();
		$ids = array_filter( $ids );

		if ( empty( $ids ) ) {
			return;
		}

		if ( 'publish' === $action ) {
			$count = BW_Schema_Survey_Publisher::publish_many( $ids );
			add_settings_error(
				'bw_schema_survey',
				'bulk_published',
				sprintf(
					/* translators: %d: count of published submissions */
					_n( '%d submission published.', '%d submissions published.', $count, 'bw-ai-schema-pro' ),
					$count
				),
				'success'
			);
		} elseif ( 'reject' === $action ) {
			$count = 0;
			foreach ( $ids as $id ) {
				if ( BW_Schema_Survey_Store::update( $id, array( 'status' => BW_Schema_Survey_Store::STATUS_REJECTED ) ) ) {
					$count++;
				}
			}
			add_settings_error(
				'bw_schema_survey',
				'bulk_rejected',
				sprintf(
					/* translators: %d: count of rejected submissions */
					_n( '%d submission rejected.', '%d submissions rejected.', $count, 'bw-ai-schema-pro' ),
					$count
				),
				'success'
			);
		}
	}

	/* ---------------- Detail ---------------- */

	public static function render_detail_page() {
		if ( ! current_user_can( BW_Schema_Survey::CAP ) ) {
			wp_die( esc_html__( 'You do not have permission to view this page.', 'bw-ai-schema-pro' ) );
		}

		$id       = isset( $_GET['id'] ) ? absint( $_GET['id'] ) : 0;
		$response = $id ? BW_Schema_Survey_Store::get( $id ) : null;
		if ( ! $response ) {
			wp_die( esc_html__( 'Submission not found.', 'bw-ai-schema-pro' ) );
		}

		// Handle posted tab-specific actions.
		self::maybe_handle_triage( $response );
		self::maybe_handle_review( $response );
		self::maybe_handle_publish( $response );

		// Re-load after any mutation.
		$response = BW_Schema_Survey_Store::get( $id );

		$tab = isset( $_GET['tab'] ) ? sanitize_key( wp_unslash( $_GET['tab'] ) ) : 'triage';
		if ( ! in_array( $tab, array( 'triage', 'review', 'publish' ), true ) ) {
			$tab = 'triage';
		}

		$questions  = BW_Schema_Survey::survey_questions();
		$field_map  = BW_Schema_Survey::field_map();
		$tpt        = BW_Schema_Team_Member::get_team_post_type();
		$team_label = $response['target_post_id'] ? get_the_title( $response['target_post_id'] ) : '';

		// Default the schema-review structured_payload deterministically on first view.
		$structured = ! empty( $response['structured_payload'] )
			? $response['structured_payload']
			: BW_Schema_Survey_Publisher::default_structured_from_raw( $response['raw_payload'] );

		$nonces = array(
			'triage'  => wp_create_nonce( self::NONCE_TRIAGE ),
			'review'  => wp_create_nonce( self::NONCE_REVIEW ),
			'publish' => wp_create_nonce( self::NONCE_PUBLISH ),
		);

		include BW_SCHEMA_PLUGIN_DIR . 'admin/views/survey-detail.php';
	}

	private static function maybe_handle_triage( $response ) {
		if ( empty( $_POST['bw_schema_survey_triage_submit'] ) ) {
			return;
		}
		if ( ! current_user_can( BW_Schema_Survey::CAP ) ) {
			wp_die( esc_html__( 'Permission denied.', 'bw-ai-schema-pro' ) );
		}
		$nonce = isset( $_POST['_bw_schema_survey_triage_nonce'] ) ? (string) wp_unslash( $_POST['_bw_schema_survey_triage_nonce'] ) : '';
		if ( ! wp_verify_nonce( $nonce, self::NONCE_TRIAGE ) ) {
			wp_die( esc_html__( 'Security check failed.', 'bw-ai-schema-pro' ) );
		}

		$id            = (int) $response['id'];
		$tpt           = BW_Schema_Team_Member::get_team_post_type();
		$target_action = isset( $_POST['target_action'] ) ? sanitize_key( wp_unslash( $_POST['target_action'] ) ) : 'link';
		$updates       = array();

		if ( 'graduate' === $target_action ) {
			// Create a new draft post in the team CPT, using the raw payload's name.
			$raw           = $response['raw_payload'];
			$new_name      = isset( $raw['full_name'] ) ? sanitize_text_field( $raw['full_name'] ) : $response['submitter_name'];
			$new_name      = '' !== $new_name ? $new_name : __( 'New team member', 'bw-ai-schema-pro' );
			$new_post_id   = wp_insert_post( array(
				'post_type'   => $tpt,
				'post_title'  => $new_name,
				'post_status' => 'draft',
			), true );
			if ( is_wp_error( $new_post_id ) || ! $new_post_id ) {
				add_settings_error( 'bw_schema_survey', 'graduate_failed', __( 'Could not create the team CPT draft.', 'bw-ai-schema-pro' ) );
				return;
			}
			$updates['target_post_id'] = $new_post_id;
		} elseif ( 'link' === $target_action ) {
			$linked = isset( $_POST['target_post_id'] ) ? absint( $_POST['target_post_id'] ) : 0;
			if ( $linked ) {
				$post = get_post( $linked );
				if ( ! $post || $post->post_type !== $tpt ) {
					add_settings_error( 'bw_schema_survey', 'link_invalid', __( "That team post doesn't exist.", 'bw-ai-schema-pro' ) );
					return;
				}
				$updates['target_post_id'] = $linked;
			}
		}

		if ( isset( $_POST['moderator_notes'] ) ) {
			$updates['moderator_notes'] = sanitize_textarea_field( wp_unslash( $_POST['moderator_notes'] ) );
		}

		// Advance status only forward — never backwards.
		if ( in_array( $response['status'], array( BW_Schema_Survey_Store::STATUS_NEW ), true ) ) {
			$updates['status'] = BW_Schema_Survey_Store::STATUS_TRIAGED;
		}

		BW_Schema_Survey_Store::update( $id, $updates );

		add_settings_error( 'bw_schema_survey', 'triage_saved', __( 'Triage saved.', 'bw-ai-schema-pro' ), 'success' );
	}

	private static function maybe_handle_review( $response ) {
		if ( empty( $_POST['bw_schema_survey_review_submit'] ) && empty( $_POST['bw_schema_survey_review_approve'] ) ) {
			return;
		}
		if ( ! current_user_can( BW_Schema_Survey::CAP ) ) {
			wp_die( esc_html__( 'Permission denied.', 'bw-ai-schema-pro' ) );
		}
		$nonce = isset( $_POST['_bw_schema_survey_review_nonce'] ) ? (string) wp_unslash( $_POST['_bw_schema_survey_review_nonce'] ) : '';
		if ( ! wp_verify_nonce( $nonce, self::NONCE_REVIEW ) ) {
			wp_die( esc_html__( 'Security check failed.', 'bw-ai-schema-pro' ) );
		}

		$id         = (int) $response['id'];
		$structured = array();
		$posted     = isset( $_POST['structured'] ) && is_array( $_POST['structured'] )
			? wp_unslash( $_POST['structured'] )
			: array();

		$field_map = BW_Schema_Survey::field_map();
		$questions = BW_Schema_Survey::survey_questions();

		// Build a quick lookup of structured_type by schema_field.
		$type_for_field = array();
		foreach ( $questions as $q ) {
			if ( ! empty( $q['schema_field'] ) ) {
				$type_for_field[ $q['schema_field'] ] = isset( $q['structured_type'] ) ? $q['structured_type'] : 'string';
			}
		}

		foreach ( $field_map as $schema_field => $meta_key ) {
			$raw  = isset( $posted[ $schema_field ] ) ? $posted[ $schema_field ] : '';
			$type = isset( $type_for_field[ $schema_field ] ) ? $type_for_field[ $schema_field ] : 'string';

			switch ( $type ) {
				case 'list':
					$structured[ $schema_field ] = BW_Schema_Survey_Publisher::prose_to_list( $raw );
					break;
				case 'url-list':
					if ( is_array( $raw ) ) {
						$urls = $raw;
					} else {
						$urls = preg_split( '/[\r\n,]+/', (string) $raw );
					}
					$structured[ $schema_field ] = array_values( array_filter( array_map( function ( $u ) {
						return esc_url_raw( trim( (string) $u ) );
					}, $urls ) ) );
					break;
				case 'int':
					$structured[ $schema_field ] = '' === $raw || null === $raw ? '' : intval( $raw );
					break;
				case 'string':
				default:
					$structured[ $schema_field ] = is_array( $raw ) ? '' : sanitize_text_field( (string) $raw );
			}
		}

		$updates = array(
			'structured_payload' => $structured,
		);

		$is_approve = ! empty( $_POST['bw_schema_survey_review_approve'] );
		if ( $is_approve ) {
			$updates['status'] = BW_Schema_Survey_Store::STATUS_READY;
		} elseif ( BW_Schema_Survey_Store::STATUS_TRIAGED === $response['status'] ) {
			$updates['status'] = BW_Schema_Survey_Store::STATUS_STRUCTURED;
		}

		BW_Schema_Survey_Store::update( $id, $updates );

		add_settings_error(
			'bw_schema_survey',
			'review_saved',
			$is_approve
				? __( 'Marked ready to publish.', 'bw-ai-schema-pro' )
				: __( 'Schema review saved.', 'bw-ai-schema-pro' ),
			'success'
		);
	}

	private static function maybe_handle_publish( $response ) {
		if ( empty( $_POST['bw_schema_survey_publish_submit'] ) ) {
			return;
		}
		if ( ! current_user_can( BW_Schema_Survey::CAP ) ) {
			wp_die( esc_html__( 'Permission denied.', 'bw-ai-schema-pro' ) );
		}
		$nonce = isset( $_POST['_bw_schema_survey_publish_nonce'] ) ? (string) wp_unslash( $_POST['_bw_schema_survey_publish_nonce'] ) : '';
		if ( ! wp_verify_nonce( $nonce, self::NONCE_PUBLISH ) ) {
			wp_die( esc_html__( 'Security check failed.', 'bw-ai-schema-pro' ) );
		}

		$ok = BW_Schema_Survey_Publisher::publish( (int) $response['id'] );
		if ( $ok ) {
			add_settings_error( 'bw_schema_survey', 'published', __( 'Published to live schema.', 'bw-ai-schema-pro' ), 'success' );
		} else {
			add_settings_error( 'bw_schema_survey', 'publish_failed', __( "Couldn't publish. Make sure the submission is marked ready and linked to a team CPT entry.", 'bw-ai-schema-pro' ) );
		}
	}

	/* ---------------- Settings ---------------- */

	public static function render_settings_page() {
		if ( ! current_user_can( BW_Schema_Survey::CAP ) ) {
			wp_die( esc_html__( 'You do not have permission to view this page.', 'bw-ai-schema-pro' ) );
		}

		self::maybe_handle_settings();

		$slug          = BW_Schema_Survey::get_slug();
		$token         = BW_Schema_Survey::get_token();
		$public_url    = BW_Schema_Survey::public_url();
		$enabled       = (int) get_option( BW_Schema_Survey::OPT_ENABLED, 0 );
		$expires_at    = BW_Schema_Survey::expires_at();
		$opens_at      = BW_Schema_Survey::opens_at();
		$days_left     = BW_Schema_Survey::days_remaining();
		$intro_html    = (string) get_option( BW_Schema_Survey::OPT_INTRO_HTML, BW_Schema_Survey::default_intro_html() );
		$notify_email  = (string) get_option( BW_Schema_Survey::OPT_NOTIFY_EMAIL, get_option( 'admin_email' ) );
		$notify_on     = (int) get_option( BW_Schema_Survey::OPT_NOTIFY_ENABLED, 0 );
		$grant_editors = (int) get_option( BW_Schema_Survey::OPT_GRANT_EDITORS, 0 );
		$tpt           = BW_Schema_Team_Member::get_team_post_type();
		$nonce         = wp_create_nonce( self::NONCE_SETTINGS );

		include BW_SCHEMA_PLUGIN_DIR . 'admin/views/survey-settings.php';
	}

	private static function maybe_handle_settings() {
		if ( empty( $_POST['bw_schema_survey_settings_submit'] ) ) {
			return;
		}
		if ( ! current_user_can( BW_Schema_Survey::CAP ) ) {
			wp_die( esc_html__( 'Permission denied.', 'bw-ai-schema-pro' ) );
		}
		$nonce = isset( $_POST['_bw_schema_survey_settings_nonce'] ) ? (string) wp_unslash( $_POST['_bw_schema_survey_settings_nonce'] ) : '';
		if ( ! wp_verify_nonce( $nonce, self::NONCE_SETTINGS ) ) {
			wp_die( esc_html__( 'Security check failed.', 'bw-ai-schema-pro' ) );
		}

		$action = sanitize_key( wp_unslash( $_POST['bw_schema_survey_settings_submit'] ) );

		switch ( $action ) {
			case 'open':
			case 'renew':
				$days = isset( $_POST['open_days'] ) ? absint( $_POST['open_days'] ) : 7;
				$days = BW_Schema_Survey::open_for_days( $days );
				add_settings_error(
					'bw_schema_survey',
					'opened',
					sprintf(
						/* translators: %d: number of days the survey will stay open */
						__( 'Survey opened for %d day(s).', 'bw-ai-schema-pro' ),
						$days
					),
					'success'
				);
				break;

			case 'close':
				BW_Schema_Survey::close();
				add_settings_error( 'bw_schema_survey', 'closed', __( 'Survey closed.', 'bw-ai-schema-pro' ), 'success' );
				break;

			case 'rotate_token':
				BW_Schema_Survey::rotate_token();
				BW_Schema_Survey::register_rewrite();
				flush_rewrite_rules( false );
				update_option( BW_Schema_Survey::OPT_REWRITE_VERSION, BW_Schema_Survey::REWRITE_VERSION, false );
				add_settings_error( 'bw_schema_survey', 'rotated', __( 'Survey URL regenerated. The old URL no longer works.', 'bw-ai-schema-pro' ), 'success' );
				break;

			case 'clear_submissions':
				$deleted = BW_Schema_Survey_Store::truncate_responses();
				add_settings_error(
					'bw_schema_survey',
					'submissions_cleared',
					sprintf(
						/* translators: %d: number of deleted submissions */
						_n(
							'%d submission deleted. Survey settings unchanged.',
							'%d submissions deleted. Survey settings unchanged.',
							$deleted,
							'bw-ai-schema-pro'
						),
						$deleted
					),
					'success'
				);
				break;

			case 'full_reset':
				// Order matters: close window first so the public URL stops
				// accepting new submissions mid-reset; then wipe the table;
				// then rotate the token + re-flush rewrites so the old URL
				// dies; then reset the rest of the settings to defaults.
				BW_Schema_Survey::close();
				$deleted = BW_Schema_Survey_Store::truncate_responses();
				BW_Schema_Survey::rotate_token();
				BW_Schema_Survey::register_rewrite();
				flush_rewrite_rules( false );
				update_option( BW_Schema_Survey::OPT_REWRITE_VERSION, BW_Schema_Survey::REWRITE_VERSION, false );

				update_option( BW_Schema_Survey::OPT_SLUG, BW_Schema_Survey::DEFAULT_SLUG );
				update_option( BW_Schema_Survey::OPT_INTRO_HTML, BW_Schema_Survey::default_intro_html() );
				update_option( BW_Schema_Survey::OPT_NOTIFY_EMAIL, get_option( 'admin_email' ) );
				update_option( BW_Schema_Survey::OPT_NOTIFY_ENABLED, 0 );
				update_option( BW_Schema_Survey::OPT_GRANT_EDITORS, 0 );
				BW_Schema_Survey::ensure_capabilities();

				add_settings_error(
					'bw_schema_survey',
					'full_reset',
					sprintf(
						/* translators: %d: number of deleted submissions */
						__( 'Survey fully reset. Window closed, URL regenerated, %d submission(s) deleted, settings restored to defaults.', 'bw-ai-schema-pro' ),
						$deleted
					),
					'success'
				);
				break;

			case 'save':
			default:
				if ( isset( $_POST['survey_slug'] ) ) {
					$new_slug = sanitize_title( wp_unslash( $_POST['survey_slug'] ) );
					if ( $new_slug && $new_slug !== BW_Schema_Survey::get_slug() ) {
						update_option( BW_Schema_Survey::OPT_SLUG, $new_slug );
						BW_Schema_Survey::register_rewrite();
						flush_rewrite_rules( false );
						update_option( BW_Schema_Survey::OPT_REWRITE_VERSION, BW_Schema_Survey::REWRITE_VERSION, false );
					}
				}
				if ( isset( $_POST['intro_html'] ) ) {
					update_option( BW_Schema_Survey::OPT_INTRO_HTML, wp_kses_post( wp_unslash( $_POST['intro_html'] ) ) );
				}
				if ( isset( $_POST['notify_email'] ) ) {
					$em = sanitize_email( wp_unslash( $_POST['notify_email'] ) );
					update_option( BW_Schema_Survey::OPT_NOTIFY_EMAIL, $em );
				}
				update_option( BW_Schema_Survey::OPT_NOTIFY_ENABLED, ! empty( $_POST['notify_enabled'] ) ? 1 : 0 );

				$grant_editors = ! empty( $_POST['grant_editors'] ) ? 1 : 0;
				update_option( BW_Schema_Survey::OPT_GRANT_EDITORS, $grant_editors );
				BW_Schema_Survey::ensure_capabilities();

				add_settings_error( 'bw_schema_survey', 'saved', __( 'Settings saved.', 'bw-ai-schema-pro' ), 'success' );
				break;
		}
	}

	/* ---------------- Inline setup (Connect / Proceed-without) ---------------- */

	/**
	 * Handle posts from `admin/views/survey-missing-team-cpt.php` — either
	 * "Connect" with a chosen post type slug, or "Proceed without". Called
	 * from the top of render_queue_page() and render_add_page() so the form
	 * submits to whichever page the user was on.
	 *
	 * @since 2.2.2
	 */
	public static function maybe_handle_setup() {
		// "Connect a team post type now" link on the proceed-without banner
		// uses a nonced GET so it can be a plain link, not a form.
		if ( isset( $_GET['bw_schema_undo_proceed_without'] ) ) {
			if ( ! current_user_can( BW_Schema_Survey::CAP ) ) {
				wp_die( esc_html__( 'Permission denied.', 'bw-ai-schema-pro' ) );
			}
			$gn = isset( $_GET['_wpnonce'] ) ? (string) wp_unslash( $_GET['_wpnonce'] ) : '';
			if ( ! wp_verify_nonce( $gn, 'bw_schema_undo_proceed_without' ) ) {
				wp_die( esc_html__( 'Security check failed.', 'bw-ai-schema-pro' ) );
			}
			update_option( BW_Schema_Survey::OPT_PROCEED_WITHOUT_TEAM_CPT, 0 );
			add_settings_error(
				'bw_schema_survey',
				'proceed_cleared',
				__( 'OK — pick a team post type below to continue.', 'bw-ai-schema-pro' ),
				'success'
			);
			// Fall through; the setup UI will now render.
		}

		if ( empty( $_POST['bw_schema_survey_setup_submit'] ) ) {
			return;
		}
		if ( ! current_user_can( BW_Schema_Survey::CAP ) ) {
			wp_die( esc_html__( 'Permission denied.', 'bw-ai-schema-pro' ) );
		}
		$nonce = isset( $_POST['_bw_schema_survey_setup_nonce'] ) ? (string) wp_unslash( $_POST['_bw_schema_survey_setup_nonce'] ) : '';
		if ( ! wp_verify_nonce( $nonce, self::NONCE_SETUP ) ) {
			wp_die( esc_html__( 'Security check failed.', 'bw-ai-schema-pro' ) );
		}

		$action = sanitize_key( wp_unslash( $_POST['bw_schema_survey_setup_submit'] ) );

		if ( 'connect' === $action ) {
			// Fallback dropdown wins over the radio (matches the UI's stated
			// behavior — "Selecting from this dropdown overrides the radio.").
			$slug_fallback = isset( $_POST['team_post_type_fallback'] )
				? sanitize_key( wp_unslash( $_POST['team_post_type_fallback'] ) )
				: '';
			$slug_radio    = isset( $_POST['team_post_type'] )
				? sanitize_key( wp_unslash( $_POST['team_post_type'] ) )
				: '';
			$slug = '' !== $slug_fallback ? $slug_fallback : $slug_radio;

			if ( ! $slug ) {
				add_settings_error( 'bw_schema_survey', 'no_slug', __( 'Pick a post type before clicking Connect.', 'bw-ai-schema-pro' ) );
				return;
			}

			if ( ! BW_Schema_Survey::set_team_post_type( $slug ) ) {
				add_settings_error(
					'bw_schema_survey',
					'bad_slug',
					sprintf(
						/* translators: %s: post type slug that couldn't be set */
						__( "Couldn't connect '%s' — that post type isn't registered on this site.", 'bw-ai-schema-pro' ),
						$slug
					)
				);
				return;
			}

			add_settings_error(
				'bw_schema_survey',
				'connected',
				sprintf(
					/* translators: %s: post type slug now mapped */
					__( 'Connected: %s is now your team post type. You can change this anytime in the main AI Schema Pro settings.', 'bw-ai-schema-pro' ),
					$slug
				),
				'success'
			);
		} elseif ( 'proceed_without' === $action ) {
			BW_Schema_Survey::set_proceed_without_team_cpt();
			add_settings_error(
				'bw_schema_survey',
				'proceed_without',
				__( "OK — proceeding without a team post type. Submissions will collect in the holding queue but can't be published until you connect one.", 'bw-ai-schema-pro' ),
				'info'
			);
		}
	}

	/* ---------------- Manual intake (admin Path 1) ---------------- */

	public static function render_add_page() {
		if ( ! current_user_can( BW_Schema_Survey::CAP ) ) {
			wp_die( esc_html__( 'You do not have permission to view this page.', 'bw-ai-schema-pro' ) );
		}

		self::maybe_handle_setup();

		if ( ! BW_Schema_Survey::is_setup_complete() ) {
			$suggestions = BW_Schema_Survey::suggest_team_post_types();
			$all_options = BW_Schema_Survey::all_eligible_post_types();
			$nonce       = wp_create_nonce( self::NONCE_SETUP );
			include BW_SCHEMA_PLUGIN_DIR . 'admin/views/survey-missing-team-cpt.php';
			return;
		}

		// If admin is in "proceed without CPT" mode, manual entry has no real
		// destination — show a friendlier message instead of the form.
		if ( BW_Schema_Survey::is_proceeding_without_cpt() ) {
			include BW_SCHEMA_PLUGIN_DIR . 'admin/views/survey-add-blocked.php';
			return;
		}

		// Handle POST (creates response, then redirects to detail/review). Render
		// the form on GET. We do the handler inline so a successful submit can
		// redirect cleanly to the new submission's review page.
		if ( ! empty( $_POST['bw_schema_survey_add_submit'] ) ) {
			self::handle_add_submit();
			// handle_add_submit() redirects on success; reaching here means we
			// fell through with a validation error message in settings_errors.
		}

		$tpt          = BW_Schema_Team_Member::get_team_post_type();
		$questions    = BW_Schema_Survey::survey_questions();
		$team_members = self::get_team_member_choices( $tpt );
		$nonce        = wp_create_nonce( self::NONCE_ADD );

		include BW_SCHEMA_PLUGIN_DIR . 'admin/views/survey-add.php';
	}

	/**
	 * Process a manual-intake form submission.
	 *
	 * Creates a survey response with status=triaged (admin is trusted — skip
	 * the moderator triage stage), runs the deterministic raw→structured
	 * parser to pre-fill structured_payload, and redirects to the Schema
	 * Review tab so the admin can refine + approve + publish.
	 */
	private static function handle_add_submit() {
		$nonce = isset( $_POST['_bw_schema_survey_add_nonce'] ) ? (string) wp_unslash( $_POST['_bw_schema_survey_add_nonce'] ) : '';
		if ( ! wp_verify_nonce( $nonce, self::NONCE_ADD ) ) {
			wp_die( esc_html__( 'Security check failed.', 'bw-ai-schema-pro' ) );
		}

		$tpt = BW_Schema_Team_Member::get_team_post_type();
		if ( ! $tpt ) {
			add_settings_error( 'bw_schema_survey', 'no_tpt', __( 'No team post type is mapped.', 'bw-ai-schema-pro' ) );
			return;
		}

		// Target.
		$target_raw       = isset( $_POST['target_post_id'] ) ? (string) wp_unslash( $_POST['target_post_id'] ) : '';
		$is_holding_queue = ( '__new__' === $target_raw );
		$target_post_id   = $is_holding_queue ? 0 : absint( $target_raw );

		if ( $target_post_id ) {
			$post = get_post( $target_post_id );
			if ( ! $post || $post->post_type !== $tpt ) {
				add_settings_error( 'bw_schema_survey', 'bad_target', __( "That team member doesn't exist.", 'bw-ai-schema-pro' ) );
				return;
			}
		}

		// Collect answers using the same shape as the public form.
		$questions = BW_Schema_Survey::survey_questions();
		$payload   = array();
		$errors    = array();

		foreach ( $questions as $q ) {
			$raw                  = isset( $_POST[ $q['key'] ] ) ? wp_unslash( $_POST[ $q['key'] ] ) : '';
			$payload[ $q['key'] ] = self::sanitize_answer_for_admin( $q, $raw );

			if ( ! empty( $q['required'] ) ) {
				$is_empty = is_array( $payload[ $q['key'] ] )
					? empty( $payload[ $q['key'] ] )
					: ( '' === trim( (string) $payload[ $q['key'] ] ) );
				if ( 'full_name' === $q['key'] && ! $is_holding_queue ) {
					continue; // Use the team CPT title instead.
				}
				if ( $is_empty ) {
					$errors[] = sprintf(
						/* translators: %s: field label */
						__( '"%s" is required.', 'bw-ai-schema-pro' ),
						$q['label']
					);
				}
			}
		}

		if ( ! empty( $errors ) ) {
			add_settings_error( 'bw_schema_survey', 'validation', implode( ' ', $errors ) );
			return;
		}

		// Determine submitter_name from chosen team CPT title or from full_name.
		$submitter_name = $is_holding_queue
			? (string) ( $payload['full_name'] ?? '' )
			: get_the_title( $target_post_id );

		// Create response.
		$id = BW_Schema_Survey_Store::insert( array(
			'target_post_id'  => $target_post_id ?: null,
			'submitter_name'  => $submitter_name,
			'submitter_email' => null,
			'submitter_ip'    => '0.0.0.0', // Admin-entered; no end-user IP.
			'raw_payload'     => $payload,
		) );

		if ( ! $id ) {
			add_settings_error( 'bw_schema_survey', 'save_failed', __( 'Could not save the submission.', 'bw-ai-schema-pro' ) );
			return;
		}

		// Skip triage — admin is trusted. Pre-fill structured_payload deterministically.
		BW_Schema_Survey_Store::update( $id, array(
			'status'             => BW_Schema_Survey_Store::STATUS_STRUCTURED,
			'structured_payload' => BW_Schema_Survey_Publisher::default_structured_from_raw( $payload ),
			'moderator_notes'    => __( 'Entered manually by admin.', 'bw-ai-schema-pro' ),
		) );

		// Redirect to Schema Review tab.
		wp_safe_redirect( self::url_detail( $id, 'review' ) );
		exit;
	}

	/**
	 * Sanitizer mirroring BW_Schema_Survey_Public::sanitize_answer(). Kept
	 * separate so the admin form doesn't depend on the public class's
	 * internals — the public class may evolve independently (e.g., the
	 * upcoming Phase 2 AI integration may extend it).
	 */
	private static function sanitize_answer_for_admin( array $question, $raw ) {
		switch ( $question['type'] ) {
			case 'textarea':
				return sanitize_textarea_field( (string) $raw );
			case 'number':
				return '' === $raw || null === $raw ? '' : max( 0, intval( $raw ) );
			case 'email':
				return sanitize_email( (string) $raw );
			case 'tel':
				return preg_replace( '/[^0-9\+\-\(\)\s]/', '', (string) $raw );
			case 'url':
				return esc_url_raw( (string) $raw );
			case 'url-list':
				$lines = is_array( $raw ) ? $raw : preg_split( '/[\r\n]+/', (string) $raw );
				$clean = array();
				foreach ( $lines as $line ) {
					$line = trim( (string) $line );
					if ( '' === $line ) {
						continue;
					}
					$url = esc_url_raw( $line );
					if ( $url ) {
						$clean[] = $url;
					}
				}
				return $clean;
			case 'text':
			default:
				return sanitize_text_field( (string) $raw );
		}
	}

	private static function get_team_member_choices( $post_type ) {
		if ( ! $post_type ) {
			return array();
		}
		$ids = get_posts( array(
			'post_type'        => $post_type,
			'post_status'      => array( 'publish', 'draft', 'private' ),
			'numberposts'      => 500,
			'orderby'          => 'title',
			'order'            => 'ASC',
			'fields'           => 'ids',
			'suppress_filters' => false,
		) );
		$out = array();
		foreach ( $ids as $pid ) {
			$title = get_the_title( $pid );
			$out[] = array(
				'id'    => (int) $pid,
				'title' => '' !== $title ? $title : sprintf( __( '(untitled #%d)', 'bw-ai-schema-pro' ), (int) $pid ),
			);
		}
		return $out;
	}

	/* ---------------- URL helpers used by views ---------------- */

	public static function url_queue( $args = array() ) {
		return add_query_arg(
			array_merge( array( 'page' => self::PAGE_QUEUE ), $args ),
			admin_url( 'options-general.php' )
		);
	}

	public static function url_detail( $id, $tab = 'triage' ) {
		return add_query_arg(
			array( 'page' => self::PAGE_DETAIL, 'id' => absint( $id ), 'tab' => sanitize_key( $tab ) ),
			admin_url( 'options-general.php' )
		);
	}

	public static function url_settings() {
		return add_query_arg( array( 'page' => self::PAGE_SETTINGS ), admin_url( 'options-general.php' ) );
	}

	public static function url_add() {
		return add_query_arg( array( 'page' => self::PAGE_ADD ), admin_url( 'options-general.php' ) );
	}
}
