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

/**
 * REST API: /wp-json/myaio/v1/site-foundation-manager
 *
 * Merged modules:
 * - check-sitemap
 * - get-robots
 * - ssl-audit
 *
 * Supported actions:
 *
 * GET:
 * - no action           => merged response with:
 *                          - check_sitemap
 *                          - get_robots
 *                          - ssl_audit
 * - action=check-sitemap
 * - action=get-robots
 * - action=ssl-audit
 *
 * POST:
 * - action=generate-sitemap
 * - action=update-robots
 *
 * Auth:
 * - Single shared auth:
 *   myaio_sac_rest_permission_check
 *
 * Note:
 * - This merged API expects the existing original module callbacks to remain loaded:
 *   - myaio_sac_check_sitemap()
 *   - myaio_sac_generate_sitemap()
 *   - myaio_sac_get_robots_txt()
 *   - myaio_sac_update_robots_txt()
 * - SSL audit is implemented locally here to avoid a second auth check.
 */

add_action(
	'rest_api_init',
	function () {
		register_rest_route(
			'myaio/v1',
			'/site-foundation-manager',
			array(
				array(
					'methods'             => WP_REST_Server::READABLE,
					'callback'            => 'myaio_site_foundation_manager_get',
					'permission_callback' => 'myaio_sac_rest_permission_check',
					'args'                => array(
						'action' => array(
							'type'              => 'string',
							'required'          => false,
							'sanitize_callback' => 'sanitize_text_field',
						),
						'url' => array(
							'type'              => 'string',
							'required'          => false,
							'sanitize_callback' => 'sanitize_text_field',
						),
					),
				),
				array(
					'methods'             => WP_REST_Server::CREATABLE,
					'callback'            => 'myaio_site_foundation_manager_post',
					'permission_callback' => 'myaio_sac_rest_permission_check',
					'args'                => array(
						'action' => array(
							'type'              => 'string',
							'required'          => true,
							'sanitize_callback' => 'sanitize_text_field',
						),
						'content' => array(
							'type'     => 'string',
							'required' => false,
						),
					),
				),
			)
		);
	}
);

/**
 * GET dispatcher.
 *
 * @param WP_REST_Request $request Request.
 * @return WP_REST_Response|WP_Error
 */
function myaio_site_foundation_manager_get( WP_REST_Request $request ) {
	$action = strtolower( trim( (string) $request->get_param( 'action' ) ) );

	if ( '' === $action ) {
		$check_sitemap = myaio_site_foundation_call_existing( 'myaio_sac_check_sitemap', $request );
		$get_robots    = myaio_site_foundation_call_existing( 'myaio_sac_get_robots_txt', $request );
		$ssl_audit     = myaio_site_foundation_ssl_audit( $request );

		return rest_ensure_response(
			array(
				'check_sitemap' => myaio_site_foundation_normalize_result_for_merge( $check_sitemap ),
				'get_robots'    => myaio_site_foundation_normalize_result_for_merge( $get_robots ),
				'ssl_audit'     => myaio_site_foundation_normalize_result_for_merge( $ssl_audit ),
			)
		);
	}

	switch ( $action ) {
		case 'check-sitemap':
			return myaio_site_foundation_call_existing( 'myaio_sac_check_sitemap', $request );

		case 'get-robots':
			return myaio_site_foundation_call_existing( 'myaio_sac_get_robots_txt', $request );

		case 'ssl-audit':
			return myaio_site_foundation_ssl_audit( $request );

		default:
			return new WP_Error(
				'invalid_action',
				'Invalid GET action. Allowed actions: check-sitemap, get-robots, ssl-audit.',
				array( 'status' => 400 )
			);
	}
}

/**
 * POST dispatcher.
 *
 * @param WP_REST_Request $request Request.
 * @return WP_REST_Response|WP_Error
 */
function myaio_site_foundation_manager_post( WP_REST_Request $request ) {
	$action = strtolower( trim( (string) $request->get_param( 'action' ) ) );

	switch ( $action ) {
		case 'generate-sitemap':
			return myaio_site_foundation_call_existing( 'myaio_sac_generate_sitemap', $request );

		case 'update-robots':
			return myaio_site_foundation_call_existing( 'myaio_sac_update_robots_txt', $request );

		default:
			return new WP_Error(
				'invalid_action',
				'Invalid POST action. Allowed actions: generate-sitemap, update-robots.',
				array( 'status' => 400 )
			);
	}
}

/**
 * Call an existing callback function safely.
 *
 * @param string          $function_name Function name.
 * @param WP_REST_Request $request Request.
 * @return mixed
 */
function myaio_site_foundation_call_existing( $function_name, WP_REST_Request $request ) {
	if ( ! function_exists( $function_name ) ) {
		return new WP_Error(
			'missing_callback',
			'Required callback not found: ' . $function_name,
			array( 'status' => 500 )
		);
	}

	return call_user_func( $function_name, $request );
}

/**
 * Normalize mixed callback results into plain arrays for merged response.
 *
 * @param mixed $result Result.
 * @return array
 */
function myaio_site_foundation_normalize_result_for_merge( $result ) {
	if ( is_wp_error( $result ) ) {
		return array(
			'error'  => $result->get_error_message(),
			'errors' => $result->errors,
			'status' => (int) $result->get_error_data( 'status' ),
		);
	}

	if ( $result instanceof WP_REST_Response ) {
		return $result->get_data();
	}

	if ( is_array( $result ) ) {
		return $result;
	}

	if ( is_object( $result ) ) {
		return (array) $result;
	}

	return array(
		'value' => $result,
	);
}

////////////////////////////////////////////////////////////////////////////////////////////////////
// SSL AUDIT (LOCAL IMPLEMENTATION TO AVOID DOUBLE AUTH)
////////////////////////////////////////////////////////////////////////////////////////////////////

/**
 * GET /myaio/v1/site-foundation-manager?action=ssl-audit&url=https://example.com
 *
 * Same output shape as old ssl-audit API.
 *
 * @param WP_REST_Request $request Request.
 * @return WP_REST_Response
 */
function myaio_site_foundation_ssl_audit( WP_REST_Request $request ) {
	$target = trim( (string) $request->get_param( 'url' ) );
	if ( '' === $target ) {
		$target = site_url( '/' );
	}

	$parsed = wp_parse_url( $target );
	if ( ! $parsed || empty( $parsed['host'] ) ) {
		return new WP_REST_Response(
			array(
				'error' => 'Invalid URL',
			),
			400
		);
	}

	$host = $parsed['host'];
	$path = isset( $parsed['path'] ) ? $parsed['path'] : '/';

	$https_url = 'https://' . $host . $path;
	$http_url  = 'http://' . $host . $path;

	$cert_info  = myaio_site_foundation_ssl_get_certificate_info( $host, 443 );
	$https_head = myaio_site_foundation_ssl_fetch_headers( $https_url, 0 );
	$http_head  = myaio_site_foundation_ssl_fetch_headers( $http_url, 0 );

	$https_final = myaio_site_foundation_ssl_fetch_headers( $https_url, 5 );
	$https_get   = myaio_site_foundation_ssl_fetch_body( $https_url );
	$link_count  = myaio_site_foundation_ssl_count_links( $https_get['body'] );

	$hsts      = myaio_site_foundation_ssl_check_hsts( $https_final['headers'] );
	$redirects = myaio_site_foundation_ssl_check_redirects( $http_head, $https_head );
	$mixed     = myaio_site_foundation_ssl_check_mixed_content( $https_get['body'] );
	$cookies   = myaio_site_foundation_ssl_check_cookie_flags( $https_final['headers'] );

	$issues = array();

	if ( ! $cert_info['valid'] ) {
		$issues[] = 'Certificate invalid (date range, host mismatch, or retrieval failed).';
	}
	if ( null !== $cert_info['days_to_expiry'] && $cert_info['days_to_expiry'] <= 30 ) {
		$issues[] = 'Certificate expires within 30 days.';
	}
	if ( ! $redirects['http_to_https'] ) {
		$issues[] = 'HTTP does not permanently redirect (301/308) to HTTPS.';
	}
	if ( ! $hsts['present'] ) {
		$issues[] = 'HSTS header missing.';
	}
	if ( $mixed['insecure_references'] > 0 ) {
		$issues[] = 'Mixed content detected (HTTP resources on HTTPS pages).';
	}
	if ( $cookies['insecure_cookies'] > 0 ) {
		$issues[] = 'Insecure cookies (missing Secure and/or SameSite).';
	}

	return rest_ensure_response(
		array(
			'summary'     => array(
				'target'    => $target,
				'host'      => $host,
				'compliant' => empty( $issues ),
				'issues'    => $issues,
			),
			'certificate' => $cert_info,
			'redirects'   => $redirects,
			'hsts'        => $hsts,
			'cookies'     => $cookies,
			'mixed'       => $mixed,
			'http'        => array(
				'head' => $http_head,
			),
			'https'       => array(
				'head'   => $https_head,
				'final'  => $https_final,
				'sample' => array(
					'status' => $https_get['status'],
					'url'    => $https_get['url'],
				),
			),
			'links'       => array(
				'http'  => array(
					'count' => $link_count['http_links'],
					'urls'  => $link_count['examples_http'],
				),
				'https' => array(
					'count' => $link_count['https_links'],
					'urls'  => $link_count['examples_https'],
				),
			),
		)
	);
}

function myaio_site_foundation_ssl_fetch_headers( $url, $redirection = 0 ) {
	$res = wp_remote_head(
		$url,
		array(
			'timeout'     => 15,
			'redirection' => $redirection,
			'sslverify'   => true,
		)
	);

	if ( is_wp_error( $res ) ) {
		return array(
			'ok'      => false,
			'status'  => 0,
			'headers' => array(),
			'error'   => $res->get_error_message(),
			'url'     => $url,
		);
	}

	return array(
		'ok'      => true,
		'status'  => (int) wp_remote_retrieve_response_code( $res ),
		'headers' => wp_remote_retrieve_headers( $res ),
		'url'     => $url,
	);
}

function myaio_site_foundation_ssl_fetch_body( $url ) {
	$res = wp_remote_get(
		$url,
		array(
			'timeout'     => 20,
			'redirection' => 5,
			'sslverify'   => true,
		)
	);

	if ( is_wp_error( $res ) ) {
		return array(
			'ok'     => false,
			'status' => 0,
			'url'    => $url,
			'body'   => '',
			'error'  => $res->get_error_message(),
		);
	}

	return array(
		'ok'     => true,
		'status' => (int) wp_remote_retrieve_response_code( $res ),
		'url'    => $url,
		'body'   => (string) wp_remote_retrieve_body( $res ),
	);
}

function myaio_site_foundation_ssl_check_redirects( $http_head, $https_head ) {
	$http_status = (int) ( $http_head['status'] ?? 0 );
	$loc         = myaio_site_foundation_ssl_header_value( $http_head['headers'] ?? array(), 'location' );

	$http_to_https = false;
	if ( in_array( $http_status, array( 301, 308 ), true ) && is_string( $loc ) && 0 === stripos( $loc, 'https://' ) ) {
		$http_to_https = true;
	}

	$https_status = (int) ( $https_head['status'] ?? 0 );
	$https_ok     = ( $https_status >= 200 && $https_status < 400 );

	return array(
		'http_status'   => $http_status,
		'http_location' => $loc,
		'http_to_https' => $http_to_https,
		'https_status'  => $https_status,
		'https_ok'      => $https_ok,
	);
}

function myaio_site_foundation_ssl_check_hsts( $headers ) {
	$hsts    = myaio_site_foundation_ssl_header_value( $headers, 'strict-transport-security' );
	$present = is_string( $hsts ) && strlen( $hsts ) > 0;

	$maxage      = null;
	$include_sub = false;
	$preload     = false;

	if ( $present ) {
		if ( preg_match( '/max-age\s*=\s*(\d+)/i', $hsts, $m ) ) {
			$maxage = (int) $m[1];
		}
		$include_sub = ( false !== stripos( $hsts, 'includesubdomains' ) );
		$preload     = ( false !== stripos( $hsts, 'preload' ) );
	}

	return array(
		'present'              => $present,
		'value'                => $hsts,
		'max_age'              => $maxage,
		'include_subdomains'   => $include_sub,
		'preload'              => $preload,
	);
}

function myaio_site_foundation_ssl_check_cookie_flags( $headers ) {
	$set_cookies = myaio_site_foundation_ssl_header_values( $headers, 'set-cookie' );
	$total       = count( $set_cookies );

	$insecure = 0;
	$samples  = array();

	foreach ( $set_cookies as $c ) {
		$has_secure   = ( false !== stripos( $c, ' secure' ) ) || preg_match( '/;\s*secure(=|;|$)/i', $c );
		$has_samesite = ( false !== stripos( $c, ' samesite' ) );

		if ( ! $has_secure || ! $has_samesite ) {
			$insecure++;
			if ( count( $samples ) < 5 ) {
				$samples[] = $c;
			}
		}
	}

	return array(
		'total_cookies'    => $total,
		'insecure_cookies' => $insecure,
		'samples'          => $samples,
	);
}

function myaio_site_foundation_ssl_check_mixed_content( $html ) {
	if ( ! is_string( $html ) || '' === $html ) {
		return array(
			'insecure_references' => 0,
			'examples'            => array(),
		);
	}

	libxml_use_internal_errors( true );
	$dom = new DOMDocument();

	// phpcs:ignore WordPress.PHP.NoSilencedErrors.Discouraged
	@$dom->loadHTML( $html );

	$xpath    = new DOMXPath( $dom );
	$count    = 0;
	$examples = array();

	foreach ( array( 'src', 'href', 'action', 'data', 'poster' ) as $att ) {
		$nodes = $xpath->query( "//*[@$att]" );
		foreach ( $nodes as $node ) {
			$val = trim( $node->getAttribute( $att ) );
			if ( 0 === stripos( $val, 'http://' ) ) {
				$count++;
				if ( count( $examples ) < 10 ) {
					$examples[] = $val;
				}
			}
		}
	}

	$imgs = $dom->getElementsByTagName( 'img' );
	foreach ( $imgs as $img ) {
		if ( $img->hasAttribute( 'srcset' ) ) {
			$srcset = $img->getAttribute( 'srcset' );
			foreach ( preg_split( '/\s*,\s*/', $srcset ) as $candidate ) {
				$parts = preg_split( '/\s+/', $candidate );
				$url   = trim( $parts[0] );
				if ( $url && 0 === stripos( $url, 'http://' ) ) {
					$count++;
					if ( count( $examples ) < 10 ) {
						$examples[] = $url;
					}
				}
			}
		}
	}

	return array(
		'insecure_references' => $count,
		'examples'            => $examples,
	);
}

function myaio_site_foundation_ssl_get_certificate_info( $host, $port = 443 ) {
	$result = array(
		'valid'          => false,
		'subject_cn'     => null,
		'issuer_cn'      => null,
		'sans'           => array(),
		'valid_from'     => null,
		'valid_to'       => null,
		'days_to_expiry' => null,
		'error'          => null,
	);

	$host = strtolower( trim( (string) $host ) );
	$port = (int) $port;

	if ( empty( $host ) ) {
		$result['error'] = 'Empty host';
		return $result;
	}

	$url = ( 443 === $port )
		? 'https://' . $host . '/'
		: 'https://' . $host . ':' . $port . '/';

	$response = wp_safe_remote_get(
		$url,
		array(
			'timeout'            => 10,
			'redirection'        => 0,
			'sslverify'          => true,
			'reject_unsafe_urls' => true,
			'sslcertificates'    => null,
		)
	);

	if ( is_wp_error( $response ) ) {
		$result['error'] = $response->get_error_message();
		return $result;
	}

	$result['valid'] = true;

	$certinfo = null;

	if ( isset( $response['http_response'] ) && is_object( $response['http_response'] ) ) {
		$raw = $response['http_response'];

		if ( method_exists( $raw, 'get_response_object' ) ) {
			$obj = $raw->get_response_object();
			if ( is_object( $obj ) && isset( $obj->certinfo ) ) {
				$certinfo = $obj->certinfo;
			}
		}
	}

	if ( is_array( $certinfo ) ) {
		if ( ! empty( $certinfo['subject']['CN'] ) ) {
			$result['subject_cn'] = (string) $certinfo['subject']['CN'];
		}
		if ( ! empty( $certinfo['issuer']['CN'] ) ) {
			$result['issuer_cn'] = (string) $certinfo['issuer']['CN'];
		}

		if ( ! empty( $certinfo['subjectAltName'] ) && is_string( $certinfo['subjectAltName'] ) ) {
			$sans = array_map( 'trim', explode( ',', $certinfo['subjectAltName'] ) );
			$sans = array_values(
				array_filter(
					array_map(
						static function ( $e ) {
							return preg_replace( '/^DNS:\s*/i', '', $e );
						},
						$sans
					)
				)
			);
			$result['sans'] = $sans;
		}

		if ( ! empty( $certinfo['validFrom_time_t'] ) ) {
			$from = (int) $certinfo['validFrom_time_t'];
			$result['valid_from'] = gmdate( 'c', $from );
		}
		if ( ! empty( $certinfo['validTo_time_t'] ) ) {
			$to = (int) $certinfo['validTo_time_t'];
			$result['valid_to'] = gmdate( 'c', $to );

			$now = time();
			$result['days_to_expiry'] = ( $to > $now ) ? (int) floor( ( $to - $now ) / 86400 ) : 0;
		}
	}

	return $result;
}

function myaio_site_foundation_ssl_header_value( $headers, $key ) {
	if ( empty( $headers ) ) {
		return null;
	}

	if ( is_object( $headers ) && method_exists( $headers, 'offsetGet' ) ) {
		$val = $headers->offsetGet( $key );
		if ( null !== $val ) {
			return is_array( $val ) ? (string) reset( $val ) : $val;
		}
	}

	foreach ( (array) $headers as $k => $v ) {
		if ( strtolower( $k ) === strtolower( $key ) ) {
			return is_array( $v ) ? (string) reset( $v ) : $v;
		}
	}

	return null;
}

function myaio_site_foundation_ssl_header_values( $headers, $key ) {
	$values = array();

	foreach ( (array) $headers as $k => $v ) {
		if ( strtolower( $k ) === strtolower( $key ) ) {
			if ( is_array( $v ) ) {
				$values = array_merge( $values, $v );
			} else {
				$values[] = $v;
			}
		}
	}

	return $values;
}

function myaio_site_foundation_ssl_count_links( $html ) {
	$result = array(
		'http_links'      => 0,
		'https_links'     => 0,
		'examples_http'   => array(),
		'examples_https'  => array(),
	);

	if ( ! is_string( $html ) || '' === trim( $html ) ) {
		return $result;
	}

	libxml_use_internal_errors( true );
	$dom = new DOMDocument();

	// phpcs:ignore WordPress.PHP.NoSilencedErrors.Discouraged
	@$dom->loadHTML( $html );

	$xpath = new DOMXPath( $dom );

	foreach ( array( 'src', 'href', 'action', 'data', 'poster' ) as $att ) {
		$nodes = $xpath->query( "//*[@$att]" );

		foreach ( $nodes as $node ) {
			$val = trim( $node->getAttribute( $att ) );

			if ( 0 === stripos( $val, 'https://' ) ) {
				$result['https_links']++;
				if ( count( $result['examples_https'] ) < 10 ) {
					$result['examples_https'][] = $val;
				}
			} elseif ( 0 === stripos( $val, 'http://' ) ) {
				$result['http_links']++;
				if ( count( $result['examples_http'] ) < 10 ) {
					$result['examples_http'][] = $val;
				}
			}
		}
	}

	return $result;
}