<?php
/**
 * Migration: Convert ambh_campaign posts to root ambh_fundraiser posts.
 *
 * For every campaign post:
 *   1. Creates a new ambh_fundraiser with post_parent=0, copying title/content/meta.
 *   2. Re-parents all fundraisers that had _ambh_campaign_id = <campaign_id>
 *      to post_parent = <new_fundraiser_id>.
 *   3. Cancels any pending ambh_end_campaign Action Scheduler jobs.
 * After all campaigns are converted:
 *   4. Deletes all remaining _ambh_campaign_id post meta across the site.
 *
 * @package AmbassadorHub\Fundraisers\Migrations
 */

namespace AmbassadorHub\Fundraisers\Migrations;

if ( ! defined( 'ABSPATH' ) ) {
	exit;
}

use AmbassadorHub\Fundraisers\FundraisersModule;

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

/**
 * One-time migration from ambh_campaign → root ambh_fundraiser.
 */
class MigrateCampaignsToFundraisers {

	private const CAMPAIGN_POST_TYPE = 'ambh_campaign';
	private const AS_HOOK            = 'ambh_end_campaign';
	private const AS_GROUP           = 'AmbassadorHub\Campaigns\CampaignsModule';

	/**
	 * Run the migration.
	 *
	 * @return void
	 */
	public static function up(): void {
		$campaigns = get_posts(
			array(
				'post_type'      => self::CAMPAIGN_POST_TYPE,
				'post_status'    => array( 'publish', 'draft', 'pending', 'private', 'ended' ),
				'posts_per_page' => -1,
				'fields'         => 'all',
				'orderby'        => 'ID',
				'order'          => 'ASC',
			)
		);

		foreach ( $campaigns as $campaign ) {
			self::migrate_campaign( $campaign );
		}

		// Remove stale _ambh_campaign_id meta from any fundraiser that wasn't
		// caught above (edge-case: orphaned fundraisers whose campaign was deleted).
		global $wpdb;
		// phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_key -- one-time upgrade migration, not a runtime hot path.
		$wpdb->delete( $wpdb->postmeta, array( 'meta_key' => '_ambh_campaign_id' ) );
	}

	// -------------------------------------------------------------------------

	private static function migrate_campaign( \WP_Post $campaign ): void {
		// Map campaign status → fundraiser status.
		$status_map = array(
			'publish' => 'publish',
			'ended'   => 'ended',
			'draft'   => 'draft',
			'pending' => 'pending',
			'private' => 'private',
		);
		$new_status = $status_map[ $campaign->post_status ] ?? 'draft';

		// Create the root fundraiser.
		$new_id = wp_insert_post(
			array(
				'post_type'    => FundraisersModule::POST_TYPE,
				'post_title'   => $campaign->post_title,
				'post_name'    => $campaign->post_name,
				'post_content' => $campaign->post_content,
				'post_excerpt' => $campaign->post_excerpt,
				'post_status'  => $new_status,
				'post_author'  => $campaign->post_author,
				'post_date'    => $campaign->post_date,
				'post_parent'  => 0,
			)
		);

		if ( is_wp_error( $new_id ) || ! $new_id ) {
			// phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_error_log
			error_log( "AmbassadorHub migration: failed to create root fundraiser for campaign {$campaign->ID}" );
			return;
		}

		// Copy campaign meta to the new root fundraiser.
		self::copy_meta( $campaign->ID, $new_id );

		// Copy featured image.
		$thumb_id = get_post_thumbnail_id( $campaign->ID );
		if ( $thumb_id ) {
			set_post_thumbnail( $new_id, $thumb_id );
		}

		// Re-parent fundraisers that belonged to this campaign.
		self::reparent_fundraisers( $campaign->ID, $new_id );

		// Cancel any pending ambh_end_campaign jobs for this campaign.
		if ( function_exists( 'as_unschedule_all_actions' ) ) {
			as_unschedule_all_actions( self::AS_HOOK, array( $campaign->ID ), self::AS_GROUP );
		}

		// Trash the campaign post so nothing references it anymore.
		wp_trash_post( $campaign->ID );
	}

	private static function copy_meta( int $from_id, int $to_id ): void {
		// Meta keys to migrate from campaign to root fundraiser.
		$keys_to_copy = array(
			'_ambh_end_date',
			'_ambh_financial_goal',
			'_ambh_teams_enabled',
			'_ambh_fundraiser_end_date_enabled',
		);

		foreach ( $keys_to_copy as $key ) {
			$value = get_post_meta( $from_id, $key, true );
			if ( '' !== $value && false !== $value ) {
				update_post_meta( $to_id, $key, $value );
			}
		}
	}

	private static function reparent_fundraisers( int $campaign_id, int $new_root_id ): void {
		global $wpdb;

		// Find all fundraisers that were linked to this campaign via _ambh_campaign_id.
		$fundraiser_ids = $wpdb->get_col(
			$wpdb->prepare(
				"SELECT post_id FROM {$wpdb->postmeta}
				 WHERE meta_key = '_ambh_campaign_id' AND meta_value = %d",
				$campaign_id
			)
		);

		if ( empty( $fundraiser_ids ) ) {
			return;
		}

		foreach ( $fundraiser_ids as $fid ) {
			$fid  = (int) $fid;
			$post = get_post( $fid );

			if ( ! $post || FundraisersModule::POST_TYPE !== $post->post_type ) {
				continue;
			}

			// Only re-parent top-level fundraisers (post_parent=0 means they were direct campaign children).
			if ( 0 !== (int) $post->post_parent ) {
				// Nested fundraisers already have a correct post_parent chain; just clean up the meta.
				delete_post_meta( $fid, '_ambh_campaign_id' );
				continue;
			}

			wp_update_post(
				array(
					'ID'          => $fid,
					'post_parent' => $new_root_id,
				)
			);

			delete_post_meta( $fid, '_ambh_campaign_id' );
		}
	}
}
