<?php
/**
 * Odysseo SEO — per-post meta box.
 *
 * Adds editable SEO fields (+ an optional "Generate with AI" button) to Posts,
 * Pages and the Destination / Tour Package / Fleet custom post types.
 *
 * @package    Odysseo
 * @author     Chandrabhan Shekhawat
 * @company    Gigai Kripa Services
 * @link       https://gigaikripaservices.com/
 * @copyright  Copyright (c) 2026, Gigai Kripa Services
 */

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

/**
 * Registers, renders and saves the SEO meta box.
 */
class Odysseo_SEO_Metabox {

	const NONCE = 'odysseo_seo_metabox';

	/**
	 * The five editable fields: key => array( label, type ).
	 *
	 * @return array
	 */
	public static function fields() {
		return array(
			'title'    => array( 'label' => __( 'SEO Title', 'odysseo-core' ),        'type' => 'text' ),
			'desc'     => array( 'label' => __( 'Meta Description', 'odysseo-core' ),  'type' => 'textarea' ),
			'keywords' => array( 'label' => __( 'Focus Keywords', 'odysseo-core' ),    'type' => 'text' ),
			'og_title' => array( 'label' => __( 'OG Title', 'odysseo-core' ),          'type' => 'text' ),
			'og_desc'  => array( 'label' => __( 'OG Description', 'odysseo-core' ),     'type' => 'textarea' ),
		);
	}

	/**
	 * Hook up.
	 */
	public function __construct() {
		add_action( 'add_meta_boxes', array( $this, 'add' ) );
		add_action( 'save_post', array( $this, 'save' ), 10, 2 );
		add_action( 'admin_enqueue_scripts', array( $this, 'enqueue' ) );
	}

	/**
	 * Register the box on each supported post type.
	 */
	public function add() {
		foreach ( odysseo_seo_post_types() as $pt ) {
			add_meta_box(
				'odysseo-seo-box',
				__( 'Odysseo SEO', 'odysseo-core' ),
				array( $this, 'render' ),
				$pt,
				'normal',
				'high'
			);
		}
	}

	/**
	 * Read a saved field value for a post.
	 *
	 * @param int    $post_id Post ID.
	 * @param string $key     Field key (without prefix).
	 * @return string
	 */
	public static function get_value( $post_id, $key ) {
		return (string) get_post_meta( $post_id, ODYSSEO_SEO_META_PREFIX . $key, true );
	}

	/**
	 * Render the box.
	 *
	 * @param WP_Post $post Current post.
	 */
	public function render( $post ) {
		wp_nonce_field( self::NONCE, self::NONCE . '_nonce' );
		$has_key = odysseo_seo_has_api_key();
		?>
		<div class="odysseo-seo-box">
			<?php foreach ( self::fields() as $key => $cfg ) :
				$id    = 'odysseo-seo-' . $key;
				$name  = 'odysseo_seo[' . $key . ']';
				$value = self::get_value( $post->ID, $key );
				?>
				<p class="odysseo-seo-field">
					<label for="<?php echo esc_attr( $id ); ?>"><strong><?php echo esc_html( $cfg['label'] ); ?></strong></label><br>
					<?php if ( 'textarea' === $cfg['type'] ) : ?>
						<textarea id="<?php echo esc_attr( $id ); ?>" name="<?php echo esc_attr( $name ); ?>" rows="2" class="widefat odysseo-seo-input" data-field="<?php echo esc_attr( $key ); ?>"><?php echo esc_textarea( $value ); ?></textarea>
					<?php else : ?>
						<input type="text" id="<?php echo esc_attr( $id ); ?>" name="<?php echo esc_attr( $name ); ?>" value="<?php echo esc_attr( $value ); ?>" class="widefat odysseo-seo-input" data-field="<?php echo esc_attr( $key ); ?>">
					<?php endif; ?>
					<?php if ( 'title' === $key ) : ?>
						<span class="odysseo-seo-hint" data-counter="title"><?php esc_html_e( 'Recommended ~60 characters.', 'odysseo-core' ); ?></span>
					<?php elseif ( 'desc' === $key ) : ?>
						<span class="odysseo-seo-hint" data-counter="desc"><?php esc_html_e( 'Recommended ~155 characters.', 'odysseo-core' ); ?></span>
					<?php endif; ?>
				</p>
			<?php endforeach; ?>

			<p class="odysseo-seo-actions">
				<?php if ( $has_key ) : ?>
					<button type="button" class="button button-secondary" id="odysseo-seo-generate" data-post="<?php echo esc_attr( $post->ID ); ?>">
						<span class="dashicons dashicons-superhero" style="vertical-align:middle"></span>
						<?php esc_html_e( 'Generate with AI', 'odysseo-core' ); ?>
					</button>
					<span class="spinner odysseo-seo-spinner" style="float:none;margin-top:0"></span>
				<?php else : ?>
					<button type="button" class="button button-secondary" disabled>
						<?php esc_html_e( 'Generate with AI', 'odysseo-core' ); ?>
					</button>
					<span class="description" style="margin-left:8px">
						<?php
						printf(
							/* translators: %s: settings page link. */
							wp_kses_post( __( 'Add an API key in <a href="%s">Settings → Odysseo SEO</a> to enable AI generation.', 'odysseo-core' ) ),
							esc_url( admin_url( 'options-general.php?page=odysseo-seo' ) )
						);
						?>
					</span>
				<?php endif; ?>
				<span class="odysseo-seo-status" role="status" aria-live="polite"></span>
			</p>
			<p class="description"><?php esc_html_e( 'AI fills these fields for you to review and edit. Nothing is published until you update the post.', 'odysseo-core' ); ?></p>
		</div>
		<?php
	}

	/**
	 * Save the fields.
	 *
	 * @param int     $post_id Post ID.
	 * @param WP_Post $post    Post object.
	 */
	public function save( $post_id, $post ) {
		if ( ! isset( $_POST[ self::NONCE . '_nonce' ] ) || ! wp_verify_nonce( sanitize_text_field( wp_unslash( $_POST[ self::NONCE . '_nonce' ] ) ), self::NONCE ) ) {
			return;
		}
		if ( defined( 'DOING_AUTOSAVE' ) && DOING_AUTOSAVE ) {
			return;
		}
		if ( ! in_array( $post->post_type, odysseo_seo_post_types(), true ) ) {
			return;
		}
		if ( ! current_user_can( 'edit_post', $post_id ) ) {
			return;
		}

		// phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized -- Each field is sanitized individually in the loop below; capability checked above.
		$in = isset( $_POST['odysseo_seo'] ) && is_array( $_POST['odysseo_seo'] ) ? wp_unslash( $_POST['odysseo_seo'] ) : array();
		foreach ( self::fields() as $key => $cfg ) {
			$raw   = isset( $in[ $key ] ) ? $in[ $key ] : '';
			$clean = 'textarea' === $cfg['type'] ? sanitize_textarea_field( $raw ) : sanitize_text_field( $raw );
			$meta  = ODYSSEO_SEO_META_PREFIX . $key;
			if ( '' === $clean ) {
				delete_post_meta( $post_id, $meta );
			} else {
				update_post_meta( $post_id, $meta, $clean );
			}
		}
	}

	/**
	 * Load the meta-box assets only on the relevant edit screens.
	 *
	 * @param string $hook Current admin page.
	 */
	public function enqueue( $hook ) {
		if ( 'post.php' !== $hook && 'post-new.php' !== $hook ) {
			return;
		}
		$screen = get_current_screen();
		if ( ! $screen || ! in_array( $screen->post_type, odysseo_seo_post_types(), true ) ) {
			return;
		}

		$min = ( defined( 'SCRIPT_DEBUG' ) && SCRIPT_DEBUG ) ? '' : '.min';
		wp_enqueue_style( 'odysseo-seo-admin', ODYSSEO_SEO_URL . '/assets/admin' . $min . '.css', array(), ODYSSEO_SEO_VER );
		wp_enqueue_script( 'odysseo-seo-admin', ODYSSEO_SEO_URL . '/assets/admin' . $min . '.js', array(), ODYSSEO_SEO_VER, true );
		wp_localize_script(
			'odysseo-seo-admin',
			'OdysseoSeo',
			array(
				'ajaxurl' => admin_url( 'admin-ajax.php' ),
				'nonce'   => wp_create_nonce( 'odysseo_seo_generate' ),
				'hasKey'  => odysseo_seo_has_api_key(),
				'i18n'    => array(
					'generating' => __( 'Generating…', 'odysseo-core' ),
					'done'       => __( 'Done — review and save the post.', 'odysseo-core' ),
					'error'      => __( 'Could not generate. Check your API key and try again.', 'odysseo-core' ),
					'saveFirst'  => __( 'Please save a draft first, then generate.', 'odysseo-core' ),
				),
			)
		);
	}
}
