<?php
if ( ! defined( 'ABSPATH' ) ) {
	exit;
}

/**
 * REST API: /wp-json/myaio/v1/page-explorer-matrix
 *
 * Query params:
 * - page (int) default 1
 * - per_page (int) default 50 (max 200)
 * - include_schema_json (bool/int) default 0
 *
 * ✅ AUTH:
 * Uses unified auth from includes/sac-utilities.php
 * - permission_callback => myaio_sac_rest_permission_check
 *
 * IMPORTANT:
 * Ensure includes/sac-utilities.php is loaded BEFORE this file.
 */

add_action( 'rest_api_init', function () {
	register_rest_route(
		'myaio/v1',
		'/page-explorer-matrix',
		array(
			'methods'             => WP_REST_Server::READABLE,
			'callback'            => 'myaio_page_explorer_matrix',

			// ✅ Unified auth (removes previous authentication)
			'permission_callback' => 'myaio_sac_rest_permission_check',

			'args'                => array(
				'page' => array(
					'type'              => 'integer',
					'default'           => 1,
					'sanitize_callback' => 'absint',
				),
				'per_page' => array(
					'type'              => 'integer',
					'default'           => 50,
					'sanitize_callback' => 'absint',
				),
				'include_schema_json' => array(
					'type'              => 'boolean',
					'default'           => false,
					'sanitize_callback' => 'rest_sanitize_boolean',
				),
			),
		)
	);
} );

/**
 * MAIN CALLBACK
 */
function myaio_page_explorer_matrix( WP_REST_Request $request ) {
	$page     = max( 1, absint( $request->get_param( 'page' ) ) );
	$per_page = absint( $request->get_param( 'per_page' ) );
	if ( $per_page < 1 ) {
		$per_page = 50;
	}
	if ( $per_page > 200 ) {
		$per_page = 200;
	}

	$include_schema_json = (bool) $request->get_param( 'include_schema_json' );

	$q = new WP_Query(
		array(
			'post_type'      => 'page',
			'post_status'    => 'publish',
			'posts_per_page' => $per_page,
			'paged'          => $page,
			'fields'         => 'ids',
			'no_found_rows'  => false,
		)
	);

	$page_ids = is_array( $q->posts ) ? $q->posts : array();

	// Load sitemap URLs (normalized)
	$sitemap_urls      = myaio_get_sitemap_urls();
	$sitemap_available = ! empty( $sitemap_urls );

	// Load robots.txt rules
	$robots_rules = myaio_parse_robots_txt();

	$results = array();

	foreach ( $page_ids as $post_id ) {
		$url = get_permalink( $post_id );
		if ( ! $url ) {
			continue;
		}

		$url = esc_url_raw( $url );

		$resp = wp_remote_get(
			$url,
			array(
				'timeout'     => 8,
				'redirection' => 3,
				'headers'     => array(
					'User-Agent' => 'MYAIO-SEO-Audit/' . ( defined( 'myaio_sac_VERSION' ) ? myaio_sac_VERSION : '1.0' ) . '; ' . home_url(),
					'Accept'     => 'text/html,application/xhtml+xml',
				),
			)
		);

		if ( is_wp_error( $resp ) ) {
			continue;
		}

		$code = (int) wp_remote_retrieve_response_code( $resp );
		if ( $code < 200 || $code >= 300 ) {
			continue;
		}

		$body = (string) wp_remote_retrieve_body( $resp );
		if ( '' === $body ) {
			continue;
		}

		// Extract schema info
		$schema_analysis = myaio_extract_schema_json( $body );

		$normalized_url = rtrim( $url, '/' );

		$results[] = array(
			'page_url' => $url,

			'no_noindex_meta_directive'       => myaio_check_noindex( $body ),
			'no_nofollow_meta_directive'      => myaio_check_nofollow( $body ),
			'allowed_by_robots_txt'           => myaio_check_robots_permission( $url, $robots_rules ),
			'all_robots_directives_are_valid' => myaio_check_valid_robots_meta( $body ),

			'canonical_link_exists'               => (bool) myaio_check_canonical_exists( $body ),
			'only_one_canonical_on_page'          => (bool) myaio_check_single_canonical( $body ),
			'canonical_url_matches_main_page_url' => (bool) myaio_check_canonical_match( $body, $url ),

			'no_inline_css'           => myaio_check_no_inline_css( $body ),
			'images_standard_formats' => myaio_check_image_formats( $body ),
			'all_images_has_alt'      => myaio_check_all_images_have_alt( $body ),
			'all_images_under_100KB'  => myaio_check_all_images_under_100kb( $body ),
			'no_deprecated_tags'      => myaio_check_deprecated_tags( $body ),
			'all_links_proper_href'   => myaio_check_links_have_href( $body ),

			'url_present_in_sitemap' => in_array( $normalized_url, $sitemap_urls, true ),
			'check_sitemap_present'  => $sitemap_available,

			'schema_exists' => (bool) $schema_analysis['exists'],
			'schema_json'   => $include_schema_json ? $schema_analysis['json'] : null,
		);
	}

	$response = rest_ensure_response( $results );

	// Helpful pagination headers
	$response->header( 'X-WP-Total', (string) (int) $q->found_posts );
	$response->header( 'X-WP-TotalPages', (string) (int) $q->max_num_pages );

	return $response;
}

////////////////////////////////////////////////////////////////////////////////////////////////////
// HELPERS
////////////////////////////////////////////////////////////////////////////////////////////////////

/**
 * Load URLs from sitemap.xml
 */
function myaio_get_sitemap_urls() {
	$sitemap  = home_url( '/sitemap.xml' );
	$response = wp_remote_get(
		$sitemap,
		array(
			'timeout'     => 5,
			'redirection' => 3,
			'headers'     => array(
				'Accept' => 'application/xml,text/xml,*/*',
			),
		)
	);

	if ( is_wp_error( $response ) ) {
		return array();
	}

	$xml = (string) wp_remote_retrieve_body( $response );
	if ( '' === $xml ) {
		return array();
	}

	$urls = array();

	if ( preg_match_all( '/<loc>(.*?)<\/loc>/i', $xml, $matches ) ) {
		foreach ( $matches[1] as $loc ) {
			$loc = trim( (string) $loc );
			if ( '' === $loc ) {
				continue;
			}
			$urls[] = rtrim( esc_url_raw( $loc ), '/' );
		}
	}

	return array_values( array_unique( $urls ) );
}

/**
 * Parse robots.txt into simple array of rules (lowercased lines).
 */
function myaio_parse_robots_txt() {
	$robots_url = home_url( '/robots.txt' );
	$response   = wp_remote_get(
		$robots_url,
		array(
			'timeout'     => 5,
			'redirection' => 3,
			'headers'     => array(
				'Accept' => 'text/plain,*/*',
			),
		)
	);

	if ( is_wp_error( $response ) ) {
		return array();
	}

	$body = strtolower( (string) wp_remote_retrieve_body( $response ) );
	if ( '' === $body ) {
		return array();
	}

	$lines = preg_split( '/\r\n|\r|\n/', $body );
	if ( ! is_array( $lines ) ) {
		return array();
	}

	return $lines;
}

/**
 * Check if allowed by robots.txt (simple Disallow prefix matching).
 */
function myaio_check_robots_permission( $url, $rules ) {
	$url  = (string) $url;
	$path = wp_parse_url( $url, PHP_URL_PATH );

	if ( ! is_string( $path ) ) {
		$path = '/';
	}

	foreach ( (array) $rules as $line ) {
		$line = trim( (string) $line );

		if ( '' === $line || strpos( $line, '#' ) === 0 ) {
			continue;
		}

		if ( strpos( $line, 'disallow:' ) === 0 ) {
			$blocked = trim( substr( $line, 9 ) );
			if ( '' !== $blocked && stripos( $path, $blocked ) === 0 ) {
				return false;
			}
		}
	}

	return true;
}

function myaio_check_noindex( $html ) {
	$html = (string) $html;
	return ! preg_match( '/<meta[^>]+robots[^>]+noindex/i', $html );
}

function myaio_check_nofollow( $html ) {
	$html = (string) $html;
	return ! preg_match( '/<meta[^>]+robots[^>]+nofollow/i', $html );
}

function myaio_check_valid_robots_meta( $html ) {
	$html = (string) $html;

	if ( ! preg_match( '/<meta[^>]+name=["\']robots["\'][^>]+content=["\']([^"\']+)["\']/i', $html, $m ) ) {
		return true;
	}

	$directives = array_map( 'trim', explode( ',', strtolower( (string) $m[1] ) ) );
	$valid      = array( 'index', 'noindex', 'follow', 'nofollow', 'noarchive', 'nosnippet', 'noimageindex' );

	foreach ( $directives as $d ) {
		if ( '' === $d ) {
			continue;
		}
		if ( ! in_array( $d, $valid, true ) ) {
			return false;
		}
	}

	return true;
}

function myaio_check_canonical_exists( $html ) {
	return (bool) preg_match( '/<link[^>]+rel=["\']canonical["\']/i', (string) $html );
}

function myaio_check_single_canonical( $html ) {
	return (int) preg_match_all( '/<link[^>]+rel=["\']canonical["\']/i', (string) $html, $m ) === 1;
}

function myaio_check_canonical_match( $html, $url ) {
	$html = (string) $html;
	$url  = (string) $url;

	if ( ! preg_match( '/<link[^>]+rel=["\']canonical["\'][^>]+href=["\']([^"\']+)["\']/i', $html, $m ) ) {
		return false;
	}

	$canon = esc_url_raw( (string) $m[1] );

	return rtrim( $url, '/' ) === rtrim( $canon, '/' );
}

function myaio_check_no_inline_css( $html ) {
	return ! preg_match( '/style=["\']/i', (string) $html );
}

function myaio_check_image_formats( $html ) {
	$html = (string) $html;

	if ( preg_match_all( '/<img[^>]+src=["\']([^"\']+)["\']/i', $html, $m ) ) {
		foreach ( $m[1] as $src ) {
			$src = (string) $src;

			// Ignore data URIs
			if ( stripos( $src, 'data:' ) === 0 ) {
				continue;
			}

			// Strip query string
			$clean = strtok( $src, '?' );
			if ( ! preg_match( '/\.(jpg|jpeg|png|svg|webp)$/i', (string) $clean ) ) {
				return false;
			}
		}
	}

	return true;
}

function myaio_check_deprecated_tags( $html ) {
	$deprecated = array( '<center', '<font', '<bgsound', '<marquee' );
	$html       = (string) $html;

	foreach ( $deprecated as $tag ) {
		if ( stripos( $html, $tag ) !== false ) {
			return false;
		}
	}

	return true;
}

function myaio_check_links_have_href( $html ) {
	$html = (string) $html;

	if ( preg_match_all( '/<a\b([^>]*)>/i', $html, $matches ) ) {
		foreach ( $matches[1] as $attr ) {
			$attr = (string) $attr;
			if ( ! preg_match( '/href=["\']([^"\']+)/i', $attr ) ) {
				return false;
			}
		}
	}

	return true;
}

/**
 * Return true if every <img> tag has a non-empty alt attribute.
 * If the page has no images, returns true.
 */
function myaio_check_all_images_have_alt( $html ) {
	$html = (string) $html;

	if ( ! preg_match_all( '/<img\b([^>]*)>/i', $html, $matches ) ) {
		return true;
	}

	foreach ( $matches[1] as $attrs ) {
		if ( ! preg_match( '/\balt\s*=\s*(["\'])(.*?)\1/i', (string) $attrs, $m ) ) {
			return false;
		}
		if ( '' === trim( (string) $m[2] ) ) {
			return false;
		}
	}

	return true;
}

/**
 * Return true if every image referenced by <img src="..."> is < 100KB.
 * If the page has no images, returns true.
 *
 * Uses Content-Length when available; otherwise falls back to downloading the image.
 * If size cannot be determined, returns false (conservative).
 */
function myaio_check_all_images_under_100kb( $html ) {
	$html = (string) $html;

	if ( ! preg_match_all( '/<img[^>]+src=["\']([^"\']+)["\']/i', $html, $m ) ) {
		return true;
	}

	$max_bytes = 100 * 1024;

	foreach ( $m[1] as $src ) {
		$bytes = myaio_get_image_size_bytes( (string) $src );

		if ( null === $bytes ) {
			return false;
		}

		if ( $bytes > $max_bytes ) {
			return false;
		}
	}

	return true;
}

/**
 * Determine image size in bytes for a given src URL.
 * Returns integer bytes, or null if unknown/unreachable.
 */
function myaio_get_image_size_bytes( $src ) {
	$src = trim( (string) $src );
	if ( '' === $src ) {
		return null;
	}

	// Data URI support (best-effort)
	if ( stripos( $src, 'data:' ) === 0 ) {
		$commaPos = strpos( $src, ',' );
		if ( false === $commaPos ) {
			return null;
		}

		$meta = substr( $src, 0, $commaPos );
		$data = substr( $src, $commaPos + 1 );

		if ( stripos( $meta, ';base64' ) !== false ) {
			$raw_len = (int) floor( strlen( $data ) * 3 / 4 );
			return $raw_len > 0 ? $raw_len : null;
		}

		$len = strlen( urldecode( $data ) );
		return $len > 0 ? $len : null;
	}

	// Normalize URL (handle relative and protocol-relative)
	if ( strpos( $src, '//' ) === 0 ) {
		$src = ( is_ssl() ? 'https:' : 'http:' ) . $src;
	} elseif ( strpos( $src, 'http://' ) !== 0 && strpos( $src, 'https://' ) !== 0 ) {
		if ( strpos( $src, '/' ) === 0 ) {
			$src = home_url( $src );
		} else {
			$src = home_url( '/' . ltrim( $src, '/' ) );
		}
	}

	$src = esc_url_raw( $src );

	// Try HEAD for Content-Length
	$head = wp_remote_head(
		$src,
		array(
			'timeout'     => 8,
			'redirection' => 3,
		)
	);

	if ( ! is_wp_error( $head ) ) {
		$len = wp_remote_retrieve_header( $head, 'content-length' );
		if ( '' !== $len && null !== $len ) {
			$len_int = (int) $len;
			if ( $len_int > 0 ) {
				return $len_int;
			}
		}
	}

	// Fallback: GET and measure body length
	$get = wp_remote_get(
		$src,
		array(
			'timeout'     => 10,
			'redirection' => 3,
		)
	);
	if ( is_wp_error( $get ) ) {
		return null;
	}

	$body = wp_remote_retrieve_body( $get );
	if ( '' === $body || null === $body ) {
		return null;
	}

	return strlen( (string) $body );
}

////////////////////////////////////////////////////////////////////////////////////////////////////
// NEW HELPERS — SCHEMA EXTRACTION
////////////////////////////////////////////////////////////////////////////////////////////////////

function myaio_extract_schema_json( $html ) {
	$result = array(
		'exists' => false,
		'json'   => null,
	);

	$html = (string) $html;

	if ( preg_match_all( '/<script[^>]+application\/ld\+json[^>]*>(.*?)<\/script>/is', $html, $matches ) ) {
		$schemas = array();

		foreach ( $matches[1] as $json_block ) {
			$json_block = trim( (string) $json_block );
			if ( '' === $json_block ) {
				continue;
			}

			$decoded = json_decode( $json_block, true );
			if ( ! empty( $decoded ) ) {
				$schemas[] = $decoded;
			}
		}

		if ( ! empty( $schemas ) ) {
			$result['exists'] = true;
			$result['json']   = $schemas;
		}
	}

	return $result;
}