<?php
/**
 * Costudio_Link_Finder
 *
 * Fetches published posts and/or pages from one or more target WP sites via
 * REST API and returns a structured array of link candidates.
 *
 * Site credentials come from the centralized ContentOS Core repository
 * (`contentos_sites`) when running as a module, or from
 * `Costudio_Standalone_Sites` when running standalone.
 *
 * @package Contentosapp_Studio
 * @since   3.0.0
 */

defined( 'ABSPATH' ) || exit;

class Costudio_Link_Finder {

	const MAX_PAGES = 10; // safety cap: 10 × 100 = 1000 posts per site

	// ── Public ───────────────────────────────────────────────────────────────

	/**
	 * Find internal links relevant to the given keywords across one or more sites.
	 *
	 * Backward compat: $site_keys may be passed as a plain string (single site).
	 *
	 * @param  string[]      $keywords   Keywords to score against.
	 * @param  string|array  $site_keys  One site key (string) or multiple (array).
	 * @param  string[]      $post_types Post types to search: 'post', 'page', or both.
	 *                                   Defaults to ['post'] to match previous behaviour.
	 * @param  int           $limit      Maximum results per site/post-type pair.
	 * @return array<int, array{
	 *   title:     string,
	 *   url:       string,
	 *   site_key:  string,
	 *   site_name: string,
	 *   post_type: string,
	 *   selected:  bool
	 * }>
	 */
	public function find( array $keywords, $site_keys, array $post_types = [ 'post' ], int $limit = 5 ): array {
		// Backward compat: accept a single string site_key.
		if ( is_string( $site_keys ) ) {
			$site_keys = [ $site_keys ];
		}

		$all_sites    = $this->resolve_sites();
		$sites_repo   = costudio_sites();
		$search_query = implode( ' ', $keywords );
		$results      = [];

		foreach ( $site_keys as $site_key ) {
			$site_key = (string) $site_key;
			$config   = $all_sites[ $site_key ] ?? [];

			if ( empty( $config ) || empty( $config['active'] ) ) {
				continue;
			}

			$site_results = $this->fetch_from_site( $site_key, $config, $search_query, $post_types, $limit );
			$results      = array_merge( $results, $site_results );
		}

		return $results;
	}

	// ── Internal ─────────────────────────────────────────────────────────────

	/**
	 * Resolve the full sites map from Core (module mode) or standalone fallback.
	 *
	 * @return array<string, array>
	 */
	private function resolve_sites(): array {
		$sites_repo = costudio_sites();

		if ( $sites_repo ) {
			return $sites_repo->get_all();
		}

		if ( class_exists( 'Costudio_Standalone_Sites' ) ) {
			return Costudio_Standalone_Sites::get_all();
		}

		return [];
	}

	/**
	 * Build credentials and fetch all requested post types from a single site.
	 *
	 * @param  string   $site_key
	 * @param  array    $config      Site config array from the sites repo.
	 * @param  string   $search_query
	 * @param  string[] $post_types
	 * @param  int      $limit
	 * @return array
	 */
	private function fetch_from_site( string $site_key, array $config, string $search_query, array $post_types, int $limit ): array {
		$base_url    = costudio_safe_http_url( rtrim( (string) ( $config['url'] ?? '' ), '/' ) );
		$user        = $config['user'] ?? '';
		$raw_password = Costudio_Sites_Crypto::decrypt( $config['password'] ?? '' );
		$auth_header = 'Basic ' . base64_encode( "{$user}:{$raw_password}" );
		$site_name   = $config['name'] ?? $site_key;

		$results     = [];
		$allowed     = [ 'post', 'page' ];

		if ( '' === $base_url ) {
			return [];
		}

		foreach ( $post_types as $post_type ) {
			if ( ! in_array( $post_type, $allowed, true ) ) {
				continue;
			}

			$endpoint = ( $post_type === 'page' ) ? 'pages' : 'posts';
			$fetched  = $this->fetch_post_type( $base_url, $auth_header, $search_query, $endpoint, $limit );

			foreach ( $fetched as $item ) {
				$results[] = [
					'title'     => html_entity_decode(
						wp_strip_all_tags( $item['title']['rendered'] ?? '' ),
						ENT_QUOTES,
						'UTF-8'
					),
					'url'       => $item['link'] ?? '',
					'site_key'  => $site_key,
					'site_name' => $site_name,
					'post_type' => $post_type,
					'selected'  => true,
				];
			}
		}

		return $results;
	}

	/**
	 * Perform the REST API call for a given post-type endpoint.
	 *
	 * @param  string $base_url
	 * @param  string $auth_header
	 * @param  string $search_query
	 * @param  string $endpoint     'posts' or 'pages'
	 * @param  int    $limit
	 * @return array  Raw WP REST items.
	 */
	private function fetch_post_type( string $base_url, string $auth_header, string $search_query, string $endpoint, int $limit ): array {
		$url = "{$base_url}/wp-json/wp/v2/{$endpoint}?" . http_build_query( [
			'status'   => 'publish',
			'per_page' => min( $limit, 100 ),
			'search'   => $search_query,
			'_fields'  => 'id,title,link',
		] );

		$response = wp_safe_remote_get( $url, costudio_safe_remote_args( [
			'timeout' => 30,
			'headers' => [ 'Authorization' => $auth_header ],
		] ) );

		if ( is_wp_error( $response ) ) {
			return [];
		}

		$data = json_decode( wp_remote_retrieve_body( $response ), true );

		return ( is_array( $data ) && ! empty( $data ) ) ? $data : [];
	}
}
