<?php
/**
 * Native WordPress provider-facing admin and CLI hooks.
 *
 * @package ScheduledChanges
 */

namespace ScheduledChanges\WordPressContent;

use ScheduledChanges\Domain\Operation\TargetDefinition;
use ScheduledChanges\Provider\ObjectContext;
use ScheduledChanges\Recording\RecordingWorkspaceMetadata;
use ScheduledChanges\Repository\RecordingSessionRepository;
use ScheduledChanges\WordPressContent\Recording\NativeWordPressWorkspaceAccessGuard;

/**
 * Publishes deterministic post/page targets without loading a module.
 */
final class NativeWordPressIntegration {
	private RecordingSessionRepository $recordings;

	/**
	 * Creates the native admin integration with recording state access.
	 */
	public function __construct( RecordingSessionRepository $recordings ) {
		$this->recordings = $recordings;
	}

	/**
	 * Registers native target discovery and presentation hooks.
	 */
	public function registerHooks(): void {
		( new NativeWordPressWorkspaceAccessGuard( $this->recordings ) )->registerHooks();
		add_filter( 'scheduled_changes_admin_target_row', array( $this, 'adminTargetRow' ), 5, 2 );
		add_filter( 'scheduled_changes_recordable_targets', array( $this, 'recordableTargets' ), 5, 2 );
		add_filter( 'scheduled_changes_provider_diagnostic_contexts', array( $this, 'diagnosticContexts' ), 5 );
		add_filter( 'scheduled_changes_validation_target_exists', array( $this, 'validationTargetExists' ), 5, 2 );
		add_filter( 'scheduled_changes_validation_target_subtype', array( $this, 'validationTargetSubtype' ), 5, 2 );
		add_filter( 'scheduled_changes_target_reference_context', array( $this, 'cliFieldScanContext' ), 5, 2 );
		add_filter( 'scheduled_changes_cli_field_scan_context', array( $this, 'cliFieldScanContext' ), 5, 2 );
	}

	/**
	 * Separates native object existence from post-type drift validation.
	 */
	public function validationTargetExists( bool $exists, TargetDefinition $target ): bool {
		if ( 'wordpress-core' !== $target->providerId() || null === $target->targetId() ) {
			return $exists;
		}

		return get_post( $target->targetId() ) instanceof \WP_Post;
	}

	/**
	 * Reports the current native post type for immutable target drift checks.
	 */
	public function validationTargetSubtype( string $subtype, TargetDefinition $target ): string {
		if ( 'wordpress-core' !== $target->providerId() || null === $target->targetId() ) {
			return $subtype;
		}

		$current = get_post_type( $target->targetId() );

		return is_string( $current ) ? $current : '';
	}

	/**
	 * @param array<string,mixed> $target Display target.
	 * @param array<string,mixed> $stored_target Stored target data.
	 * @return array<string,mixed>
	 */
	public function adminTargetRow( array $target, array $stored_target ): array {
		$provider_id = (string) ( $target['providerId'] ?? $stored_target['provider_id'] ?? $stored_target['source_provider_id'] ?? '' );
		$target_type = (string) ( $target['targetType'] ?? $stored_target['target_type'] ?? $stored_target['source_type'] ?? '' );

		if ( 'wordpress-core' !== $provider_id && ! in_array( $target_type, array( 'post', 'page' ), true ) ) {
			return $target;
		}

		$post_id = (int) ( $target['id'] ?? $stored_target['target_id'] ?? $stored_target['source_id'] ?? 0 );
		$post    = $post_id > 0 ? get_post( $post_id ) : null;

		if ( ! $post instanceof \WP_Post || ! in_array( $post->post_type, array( 'post', 'page' ), true ) ) {
			return $target;
		}

		$edit_url    = get_edit_post_link( $post_id, 'raw' );
		$view_url    = get_permalink( $post_id );
		$thumbnail   = wp_get_attachment_image_url( (int) get_post_thumbnail_id( $post_id ), 'thumbnail' );
		$reference   = $post->post_type . ':' . $post_id;
		$target_type = $post->post_type;

		$target['id']              = $post_id;
		$target['providerId']      = 'wordpress-core';
		$target['providerLabel']   = __( 'WordPress', 'jjs-post-scheduler' );
		$target['targetType']      = $target_type;
		$target['subtype']         = $post->post_type;
		$target['typeLabel']       = 'page' === $post->post_type ? __( 'Page', 'jjs-post-scheduler' ) : __( 'Post', 'jjs-post-scheduler' );
		$target['icon']            = 'file';
		$target['targetReference'] = $reference;
		$target['reference']       = $reference;
		$target['name']            = '' !== trim( get_the_title( $post ) ) ? get_the_title( $post ) : __( '(no title)', 'jjs-post-scheduler' );
		$target['editUrl']         = is_string( $edit_url ) ? $edit_url : '';
		$target['viewUrl']         = is_string( $view_url ) ? $view_url : '';
		$target['thumbnail']       = is_string( $thumbnail ) ? $thumbnail : '';
		$target['capability']      = 'edit_post';
		$target['canEdit']         = current_user_can( 'edit_post', $post_id );

		return $target;
	}

	/**
	 * @param array<int,array<string,mixed>> $targets Existing provider targets.
	 * @return array<int,array<string,mixed>>
	 */
	public function recordableTargets( array $targets, int $limit ): array {
		$post_ids = get_posts(
			array(
				'post_type'      => array( 'post', 'page' ),
				'post_status'    => array( 'publish', 'future', 'draft', 'pending', 'private' ),
				'posts_per_page' => max( 1, min( 100, $limit ) ),
				'orderby'        => array(
					'modified' => 'DESC',
					'ID'       => 'DESC',
				),
				'fields'         => 'ids',
				'meta_query'     => array( // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_query -- Bounded admin selector excludes private recording copies.
					array(
						'key'     => RecordingWorkspaceMetadata::NATIVE_MARKER,
						'compare' => 'NOT EXISTS',
					),
				),
			)
		);

		foreach ( is_array( $post_ids ) ? $post_ids : array() as $post_id ) {
			if ( ! current_user_can( 'edit_post', (int) $post_id ) ) {
				continue;
			}

			$row = $this->adminTargetRow(
				array(
					'providerId' => 'wordpress-core',
					'id'         => (int) $post_id,
				),
				array()
			);

			if ( isset( $row['targetReference'] ) ) {
				$targets[] = $row;
			}
		}

		return $targets;
	}

	/**
	 * @param ObjectContext[] $contexts Existing contexts.
	 * @return ObjectContext[]
	 */
	public function diagnosticContexts( array $contexts ): array {
		foreach ( array( 'post', 'page' ) as $post_type ) {
			$post_ids = get_posts(
				array(
					'post_type'      => $post_type,
					'post_status'    => 'any',
					'posts_per_page' => 1,
					'orderby'        => 'ID',
					'order'          => 'ASC',
					'fields'         => 'ids',
					'meta_query'     => array( // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_query -- Diagnostic context must not select a recording copy.
						array(
							'key'     => RecordingWorkspaceMetadata::NATIVE_MARKER,
							'compare' => 'NOT EXISTS',
						),
					),
				)
			);

			if ( isset( $post_ids[0] ) ) {
				$contexts[] = new ObjectContext( $post_type, (int) $post_ids[0], $post_type );
			}
		}

		return $contexts;
	}

	/**
	 * Resolves a prefixed native target reference for WP-CLI field scans.
	 */
	public function cliFieldScanContext( ?ObjectContext $context, string $target_reference ): ?ObjectContext {
		if ( $context instanceof ObjectContext || ! preg_match( '/^(post|page):([1-9][0-9]*)$/', $target_reference, $matches ) ) {
			return $context;
		}

		$post_type = $matches[1];
		$post_id   = (int) $matches[2];

		return get_post_type( $post_id ) === $post_type
			? new ObjectContext( $post_type, $post_id, $post_type )
			: null;
	}
}
