<?php
/**
 * Backup Manager (Link Architect).
 *
 * Per-post backups stored as postmeta with the
 * `_platform_helm_lk_backup_{timestamp}_{rand}` key shape.
 *
 * Each backup payload contains:
 *   - post_content    (pre-modification)
 *   - _elementor_data (pre-modification)
 *   - phrase          (the phrase that was wrapped)
 *   - orphan_url      (the URL the phrase was wrapped with)
 *   - timestamp
 *
 * @package Platform\Helm\Modules\Link_Architect
 */

declare( strict_types = 1 );

namespace Platform\Helm\Modules\Link_Architect;

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

final class BackupManager {

	/**
	 * Create a backup for a source post about to be modified.
	 * Returns the backup meta key.
	 */
	public function create_backup( int $post_id, string $post_content, string $elementor_data, string $phrase, string $orphan_url ): string {
		$key = LinkArchitectModule::BACKUP_META_PREFIX
			. time() . '_'
			. wp_generate_password( 4, false, false );

		$payload = wp_json_encode( [
			'post_content'    => $post_content,
			'_elementor_data' => $elementor_data,
			'phrase'          => $phrase,
			'orphan_url'      => $orphan_url,
			'timestamp'       => time(),
		], JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE );

		if ( false === $payload ) {
			$payload = '{}';
		}
		update_post_meta( $post_id, $key, wp_slash( $payload ) );
		return $key;
	}

	/**
	 * List all backups across all posts. Newest first.
	 *
	 * @return array<int,array<string,mixed>>
	 */
	public function list_all(): array {
		global $wpdb;
		$like = $wpdb->esc_like( LinkArchitectModule::BACKUP_META_PREFIX ) . '%';
		// phpcs:ignore WordPress.DB.DirectDatabaseQuery, WordPress.DB.PreparedSQL.NotPrepared
		$rows = $wpdb->get_results( $wpdb->prepare(
			"SELECT meta_id, post_id, meta_key, meta_value
			 FROM {$wpdb->postmeta}
			 WHERE meta_key LIKE %s
			 ORDER BY meta_id DESC",
			$like
		), ARRAY_A );

		if ( ! is_array( $rows ) ) {
			return [];
		}
		$out = [];
		foreach ( $rows as $row ) {
			$decoded = json_decode( (string) $row['meta_value'], true );
			if ( ! is_array( $decoded ) ) {
				$decoded = [];
			}
			$post = get_post( (int) $row['post_id'] );
			$out[] = [
				'meta_id'    => (int) $row['meta_id'],
				'post_id'    => (int) $row['post_id'],
				'meta_key'   => (string) $row['meta_key'],
				'post_title' => $post ? $post->post_title : sprintf( /* translators: %d: post ID */ __( '(deleted post #%d)', 'platform-helm' ), (int) $row['post_id'] ),
				'post_type'  => $post ? $post->post_type : '',
				'phrase'     => (string) ( $decoded['phrase']     ?? '' ),
				'orphan_url' => (string) ( $decoded['orphan_url'] ?? '' ),
				'timestamp'  => (int)    ( $decoded['timestamp']  ?? 0 ),
			];
		}
		return $out;
	}

	public function count_all(): int {
		global $wpdb;
		$like = $wpdb->esc_like( LinkArchitectModule::BACKUP_META_PREFIX ) . '%';
		// phpcs:ignore WordPress.DB.DirectDatabaseQuery, WordPress.DB.PreparedSQL.NotPrepared
		return (int) $wpdb->get_var( $wpdb->prepare(
			"SELECT COUNT(*) FROM {$wpdb->postmeta} WHERE meta_key LIKE %s",
			$like
		) );
	}

	/**
	 * Restore the post to its pre-modification state.
	 *
	 * @return array{ok:bool,message:string}
	 */
	public function restore( int $post_id, string $meta_key ): array {
		if ( 0 !== strpos( $meta_key, LinkArchitectModule::BACKUP_META_PREFIX ) ) {
			return [ 'ok' => false, 'message' => __( 'Invalid backup key.', 'platform-helm' ) ];
		}
		$payload_raw = get_post_meta( $post_id, $meta_key, true );
		if ( ! is_string( $payload_raw ) || '' === $payload_raw ) {
			return [ 'ok' => false, 'message' => __( 'Backup not found.', 'platform-helm' ) ];
		}
		$payload = json_decode( $payload_raw, true );
		if ( ! is_array( $payload ) ) {
			return [ 'ok' => false, 'message' => __( 'Backup payload corrupt.', 'platform-helm' ) ];
		}

		$updated = wp_update_post( [
			'ID'           => $post_id,
			'post_content' => (string) ( $payload['post_content'] ?? '' ),
		], true );
		if ( is_wp_error( $updated ) ) {
			return [ 'ok' => false, 'message' => $updated->get_error_message() ];
		}

		// Restore Elementor data if present.
		if ( isset( $payload['_elementor_data'] ) && '' !== $payload['_elementor_data'] ) {
			update_post_meta( $post_id, '_elementor_data', wp_slash( (string) $payload['_elementor_data'] ) );
			// Clear Elementor cache for this post if available.
			if ( class_exists( '\Elementor\Plugin' ) ) {
				try {
					\Elementor\Plugin::$instance->files_manager->clear_cache();
				} catch ( \Throwable $e ) {
					// Non-fatal.
				}
			}
		}

		// Remove the backup now that we've restored.
		delete_post_meta( $post_id, $meta_key );

		// The restore reverts content to before our insertions, so the links
		// we recorded for this source no longer exist. Clear them from
		// LinkMemory, allowing the Suggester to surface them again.
		( new \Platform\Helm\Core\LinkMemory() )->forget_all_for( $post_id );

		/**
		 * Fires after a successful restore from a link backup. Activity Log
		 * listens for this.
		 *
		 * @param int $post_id The post that was restored.
		 */
		do_action( 'platform_helm_link_restored', $post_id );

		return [ 'ok' => true, 'message' => __( 'Restored successfully.', 'platform-helm' ) ];
	}

	public function delete( int $post_id, string $meta_key ): bool {
		if ( 0 !== strpos( $meta_key, LinkArchitectModule::BACKUP_META_PREFIX ) ) {
			return false;
		}
		return (bool) delete_post_meta( $post_id, $meta_key );
	}
}
