<?php
/**
 * Migration 025: Remove same-site canonical URL overrides
 *
 * Cleans up incorrect canonical_url meta set by WiseWand on same-site posts.
 * The API URL (no trailing slash) was being written as a custom canonical override,
 * causing canonical mismatch and sitemap exclusion.
 *
 * Only removes canonicals pointing to the same site. Cross-domain canonicals
 * (syndicated/republished content) are preserved.
 *
 * @package Wisewand
 * @subpackage Database\Migrations
 * @since 2.8.0
 * @license GPL-2.0-or-later
 */

namespace Wisewand\Database\Migrations;

// Exit if accessed directly.
if ( ! defined( 'ABSPATH' ) ) {
	exit;
}

// phpcs:disable WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, WordPress.DB.PreparedSQL.InterpolatedNotPrepared

/**
 * Migration 025 Class
 *
 * Removes same-site canonical URL overrides from Rank Math, Yoast, and SEOPress
 * for posts created by WiseWand, and invalidates sitemap caches.
 *
 * @since 2.8.0
 */
class Migration_025_Remove_Same_Site_Canonicals {

	/**
	 * Run the migration
	 *
	 * Finds WiseWand posts with same-site canonical overrides and removes them.
	 * Idempotent — safe to run multiple times.
	 *
	 * @param \wpdb $wpdb WordPress database instance.
	 * @return bool True on success, false on failure.
	 */
	public static function up( $wpdb ) {
		$site_host = wp_parse_url( home_url(), PHP_URL_HOST );

		if ( empty( $site_host ) ) {
			if ( defined( 'WP_DEBUG' ) && WP_DEBUG ) {
				error_log( 'Wisewand Migration 025: Could not determine site host, skipping' );
			}
			return false;
		}

		// Strip www. for matching
		$site_host_bare = preg_replace( '/^www\./i', '', $site_host );

		if ( defined( 'WP_DEBUG' ) && WP_DEBUG ) {
			error_log( 'Wisewand Migration 025: Removing same-site canonical overrides for host: ' . $site_host_bare );
		}

		$canonical_meta_keys = array(
			'rank_math_canonical_url',
			'_yoast_wpseo_canonical',
			'_seopress_robots_canonical',
		);

		$total_deleted = 0;

		$wpdb->query( 'START TRANSACTION' );

		foreach ( $canonical_meta_keys as $meta_key ) {
			// Find and delete canonical meta for WiseWand posts pointing to same site
			// Uses INNER JOIN to only affect posts that have _wisewand_external_id (WiseWand posts)
			// Uses LIKE to match both www. and non-www. variants
			// phpcs:ignore PluginCheck.Security.DirectDB.UnescapedDBParameter
			$deleted = $wpdb->query(
				$wpdb->prepare(
					"DELETE cm FROM {$wpdb->postmeta} cm
					INNER JOIN {$wpdb->postmeta} wm
						ON cm.post_id = wm.post_id
						AND wm.meta_key = '_wisewand_external_id'
					WHERE cm.meta_key = %s
					AND ( cm.meta_value LIKE %s OR cm.meta_value LIKE %s )",
					$meta_key,
					'%' . $wpdb->esc_like( $site_host_bare ) . '%',
					'%www.' . $wpdb->esc_like( $site_host_bare ) . '%'
				)
			);

			if ( false === $deleted ) {
				$wpdb->query( 'ROLLBACK' );
				if ( defined( 'WP_DEBUG' ) && WP_DEBUG ) {
					error_log( 'Wisewand Migration 025: Error deleting ' . $meta_key . ' — ' . $wpdb->last_error );
				}
				return false;
			}

			if ( defined( 'WP_DEBUG' ) && WP_DEBUG ) {
				error_log( 'Wisewand Migration 025: Deleted ' . $deleted . ' same-site ' . $meta_key . ' entries' );
			}

			$total_deleted += $deleted;
		}

		$wpdb->query( 'COMMIT' );

		// Invalidate sitemap caches
		if ( class_exists( '\\RankMath\\Sitemap\\Cache' ) ) {
			\RankMath\Sitemap\Cache::invalidate_storage();
		}

		$upload_dir     = wp_upload_dir();
		$rankmath_cache = $upload_dir['basedir'] . '/rank-math/';
		if ( is_dir( $rankmath_cache ) ) {
			$files = glob( $rankmath_cache . '*.xml' );
			if ( $files ) {
				foreach ( $files as $file ) {
					wp_delete_file( $file );
				}
			}
		}

		if ( class_exists( '\\WPSEO_Sitemaps_Cache' ) ) {
			\WPSEO_Sitemaps_Cache::clear();
		}

		if ( defined( 'WP_DEBUG' ) && WP_DEBUG ) {
			error_log( 'Wisewand Migration 025: Completed — removed ' . $total_deleted . ' same-site canonical overrides total' );
		}

		return true;
	}

	/**
	 * Rollback the migration
	 *
	 * No rollback needed — the canonical overrides were incorrect.
	 * Restoring them would reintroduce the bug.
	 *
	 * @param \wpdb $wpdb WordPress database instance.
	 * @return bool Always true.
	 */
	public static function down( $wpdb ) {
		return true;
	}
}
// phpcs:enable WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, WordPress.DB.PreparedSQL.InterpolatedNotPrepared
