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

/**
 * REST API Endpoint:
 * /wp-json/myaio/v1/backlink-explorer?key=YOUR_KEY
 */

add_action(
	'rest_api_init',
	function () {
		register_rest_route(
			'myaio/v1',
			'/backlink-explorer',
			[
				'methods'             => 'GET',
				'callback'            => 'myaio_backlink_explorer',
				'permission_callback' => 'myaio_sac_rest_permission_check', // ✅ unified auth
				'args'                => [
					'key' => [
						'required' => true,
						'type'     => 'string',
					],
					'url' => [
						'required' => false,
						'type'     => 'string',
					],
				],
			]
		);
	}
);

/* ================================================================
 * MAIN CALLBACK
 * ================================================================ */
function myaio_backlink_explorer( WP_REST_Request $request ) {

	if ( ! function_exists( 'myaio_sac_get_all_crawlable_urls' ) ) {
		return new WP_REST_Response(
			[
				'error' => 'Required function myaio_sac_get_all_crawlable_urls() not found.',
			],
			500
		);
	}

	$all_pages = myaio_sac_get_all_crawlable_urls();
	if ( ! is_array( $all_pages ) ) {
		return new WP_REST_Response(
			[
				'error' => 'myaio_sac_get_all_crawlable_urls() did not return an array.',
			],
			500
		);
	}

	// If a specific `url` param was provided, restrict processing to that URL only.
	$requested = $request->get_param( 'url' );
	if ( ! empty( $requested ) ) {
		$requested = (string) $requested;

		// allow site-root relative paths like "/path" → convert to full URL
		if ( strpos( $requested, '/' ) === 0 ) {
			$requested = rtrim( home_url( $requested ), '/' );
		}
		$requested = rtrim( $requested, '/' );

		$found = null;
		foreach ( $all_pages as $p ) {
			if ( ! is_array( $p ) || empty( $p['url'] ) ) {
				continue;
			}
			if ( rtrim( (string) $p['url'], '/' ) === $requested ) {
				$found = $p;
				break;
			}
		}

		if ( $found ) {
			$all_pages = [ $found ];
		} else {
			// If not found in sitemap/crawl list, still attempt the single URL.
			$all_pages = [
				[
					'url'      => $requested,
					'type'     => null,
					'category' => null,
				],
			];
		}
	}

	$incoming_map = [];
	$results      = [];

	$site_home = rtrim( home_url(), '/' );

	foreach ( $all_pages as $page ) {

		if ( ! is_array( $page ) || empty( $page['url'] ) ) {
			continue;
		}

		$url = rtrim( (string) $page['url'], '/' );

		$response = wp_remote_get(
			$url,
			[
				'timeout'     => 15,
				'redirection' => 5,
				'user-agent'  => 'myaio-backlink-explorer/1.1; ' . $site_home,
			]
		);

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

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

		$html = wp_remote_retrieve_body( $response );
		if ( empty( $html ) ) {
			continue;
		}

		// Extract links
		$outgoing = myaio_extract_links_with_context( $html, $site_home );

		// Build incoming link map
		foreach ( $outgoing['all_links'] as $lnk ) {
			$target = rtrim( $lnk['href'], '/' );
			if ( ! isset( $incoming_map[ $target ] ) ) {
				$incoming_map[ $target ] = [];
			}
			$incoming_map[ $target ][] = [
				'from_url'  => $url,
				'anchor'    => $lnk['anchor'],
				'nofollow'  => $lnk['nofollow'],
				'snippet'   => $lnk['html_snippet'],
				'placement' => $lnk['placement'],
			];
		}

		$results[ $url ] = [
			'url'      => $url,
			'type'     => $page['type'] ?? null,
			'category' => $page['category'] ?? null,

			'outgoing_internal_links' => $outgoing['internal_links'],
			'outgoing_external_links' => $outgoing['external_links'],

			'outgoing_summary'        => [
				'internal' => count( $outgoing['internal_links'] ),
				'external' => count( $outgoing['external_links'] ),
				'nofollow' => $outgoing['nofollow_count'],
				'dofollow' => $outgoing['dofollow_count'],
			],

			'incoming_internal_links' => [],
			'incoming_external_links' => [],
		];
	}

	/* Attach incoming links */
	foreach ( $results as $page_url => &$data ) {
		$normalized = rtrim( (string) $page_url, '/' );
		$incoming   = $incoming_map[ $normalized ] ?? [];

		$data['incoming_internal_links'] = array_values(
			array_filter(
				$incoming,
				function ( $i ) use ( $site_home ) {
					return strpos( rtrim( (string) $i['from_url'], '/' ), $site_home ) === 0;
				}
			)
		);

		$data['incoming_external_links'] = array_values(
			array_filter(
				$incoming,
				function ( $i ) use ( $site_home ) {
					return strpos( rtrim( (string) $i['from_url'], '/' ), $site_home ) !== 0;
				}
			)
		);
	}
	unset( $data );

	return rest_ensure_response(
		[
			'total_pages' => count( $results ),
			'pages'       => array_values( $results ),
		]
	);
}

/* ================================================================
 * LINK EXTRACTION — WITH RAW REL CHECK + PLACEMENT
 * ================================================================ */
function myaio_extract_links_with_context( $html, $site_home ) {

	libxml_use_internal_errors( true );

	$dom = new DOMDocument();

	// Suppress warnings from imperfect HTML.
	// phpcs:ignore WordPress.PHP.NoSilencedErrors.Discouraged
	@$dom->loadHTML( '<?xml encoding="UTF-8">' . $html );

	$links = $dom->getElementsByTagName( 'a' );

	$internal = [];
	$external = [];
	$all      = [];

	$nofollow_count = 0;
	$dofollow_count = 0;

	foreach ( $links as $link ) {

		$href = trim( (string) $link->getAttribute( 'href' ) );
		if ( ! $href ) {
			continue;
		}

		// ignore mailto, tel, javascript, anchors
		$l = strtolower( $href );
		if ( preg_match( '/^(mailto:|tel:|javascript:|#)/i', $l ) ) {
			continue;
		}

		// Convert relative → absolute
		if ( strpos( $href, '/' ) === 0 ) {
			$href = home_url( $href );
		}

		// Validate http(s)
		if ( ! preg_match( '/^https?:\/\//i', $href ) ) {
			continue;
		}

		$href = rtrim( $href, '/' );

		// Extract raw snippet from DOM
		$snippet_dom = $dom->saveHTML( $link );

		// Extract real rel attribute using regex from original HTML
		$raw_rel = null;
		if ( preg_match( '/<a[^>]+href=["\']' . preg_quote( $href, '/' ) . '["\'][^>]*>/i', $html, $matchA ) ) {
			if ( preg_match( '/rel=["\']([^"\']+)["\']/i', $matchA[0], $relMatch ) ) {
				$raw_rel = strtolower( $relMatch[1] );
			}
		}

		// Correct nofollow detection
		$nofollow = false;
		if ( ! empty( $raw_rel ) ) {
			$rel_parts = preg_split( '/\s+/', $raw_rel );
			$nofollow  = in_array( 'nofollow', $rel_parts, true );
		}

		if ( $nofollow ) {
			$nofollow_count++;
		} else {
			$dofollow_count++;
		}

		// Anchor text
		$anchor = trim( (string) $link->textContent );

		// Placement
		$placement = myaio_detect_link_location( $link );

		$info = [
			'href'         => $href,
			'anchor'       => $anchor,
			'nofollow'     => $nofollow,
			'dofollow'     => ! $nofollow,
			'html_snippet' => $snippet_dom,
			'placement'    => $placement,
		];

		if ( strpos( $href, $site_home ) === 0 ) {
			$internal[] = $info;
		} else {
			$external[] = $info;
		}

		$all[] = $info;
	}

	return [
		'internal_links' => $internal,
		'external_links' => $external,
		'all_links'      => $all,
		'nofollow_count' => $nofollow_count,
		'dofollow_count' => $dofollow_count,
	];
}

/* ================================================================
 * LINK LOCATION DETECTOR
 * ================================================================ */
function myaio_detect_link_location( DOMNode $node ) {

	while ( $node && $node->nodeName ) {

		$tag = strtolower( (string) $node->nodeName );

		if ( 'header' === $tag || myaio_node_has_class( $node, [ 'header', 'site-header', 'main-header' ] ) ) {
			return 'header';
		}
		if ( 'nav' === $tag || myaio_node_has_class( $node, [ 'menu', 'navbar', 'main-menu' ] ) ) {
			return 'navigation';
		}
		if ( 'footer' === $tag || myaio_node_has_class( $node, [ 'footer', 'site-footer' ] ) ) {
			return 'footer';
		}
		if ( 'aside' === $tag || myaio_node_has_class( $node, [ 'sidebar', 'widget-area' ] ) ) {
			return 'sidebar';
		}

		if ( myaio_node_has_class( $node, [ 'elementor-section', 'elementor-widget', 'elementor-column' ] ) ) {
			return 'elementor-section';
		}
		if ( myaio_node_has_class( $node, [ 'wp-block', 'wp-block-group' ] ) ) {
			return 'gutenberg-block';
		}

		if ( myaio_node_has_class( $node, [ 'entry-content', 'post-content', 'page-content', 'content' ] ) ) {
			return 'content';
		}

		$node = $node->parentNode;
	}

	return 'body';
}

function myaio_node_has_class( $node, array $classes ) {
	if ( ! $node->attributes ) {
		return false;
	}

	$attr = $node->attributes->getNamedItem( 'class' );
	if ( ! $attr ) {
		return false;
	}

	$val = strtolower( (string) $attr->nodeValue );

	foreach ( $classes as $check ) {
		if ( strpos( $val, strtolower( (string) $check ) ) !== false ) {
			return true;
		}
	}
	return false;
}