<?php
/**
 * Persistence — post meta JSON document (not HTML).
 *
 * @package AuraBuilder
 */

declare(strict_types=1);

namespace AuraBuilder\Storage;

use AuraBuilder\Document\Document;
use AuraBuilder\Document\DocumentSanitizer;
use AuraBuilder\Import\ContentImporter;

final class DocumentRepository {

	/**
	 * @return array{document:Document,source:string,imported:bool}
	 */
	public function get_with_meta( int $post_id ): array {
		$raw = $this->read_raw_document( $post_id );
		if ( is_array( $raw ) && ! empty( $raw['nodes'] ) ) {
			// Normalize root id key (older saves used root_id).
			if ( empty( $raw['rootId'] ) && ! empty( $raw['root_id'] ) ) {
				$raw['rootId'] = $raw['root_id'];
			}
			if ( ! empty( $raw['rootId'] ) || ! empty( $raw['root_id'] ) ) {
				return array(
					'document' => DocumentSanitizer::sanitize( $raw ),
					'source'   => 'saved',
					'imported' => false,
				);
			}
		}

		// No saved builder doc → import Elementor / legacy / post_content.
		$doc = ( new ContentImporter() )->from_post( $post_id );
		return array(
			'document' => $doc,
			'source'   => (string) ( $doc->metadata['importedFrom'] ?? 'empty' ),
			'imported' => true,
		);
	}

	/**
	 * Read document array from new meta key, then legacy key.
	 * Empty string / empty array / invalid JSON must fall through to legacy —
	 * otherwise a blank _aptb_document hides a full _aura_builder_document.
	 *
	 * @return array<string, mixed>
	 */
	private function read_raw_document( int $post_id ): array {
		$keys = array( AURA_BUILDER_META_DOC );
		if ( defined( 'AURA_BUILDER_META_DOC_LEGACY' ) ) {
			$keys[] = AURA_BUILDER_META_DOC_LEGACY;
		}

		foreach ( $keys as $key ) {
			$raw = get_post_meta( $post_id, $key, true );
			$arr = $this->normalize_meta_value( $raw );
			if ( ! empty( $arr['nodes'] ) && is_array( $arr['nodes'] ) ) {
				return $arr;
			}
		}

		return array();
	}

	/**
	 * @param mixed $raw
	 * @return array<string, mixed>
	 */
	private function normalize_meta_value( $raw ): array {
		if ( is_array( $raw ) ) {
			return $raw;
		}
		if ( ! is_string( $raw ) || $raw === '' ) {
			return array();
		}
		$decoded = json_decode( $raw, true );
		if ( is_array( $decoded ) ) {
			return $decoded;
		}
		// WP may store PHP-serialized arrays as a string in some edge cases.
		$un = maybe_unserialize( $raw );
		return is_array( $un ) ? $un : array();
	}

	public function get( int $post_id ): Document {
		return $this->get_with_meta( $post_id )['document'];
	}

	public function is_enabled( int $post_id ): bool {
		$on = get_post_meta( $post_id, AURA_BUILDER_META_ON, true );
		if ( $on === '1' ) {
			return true;
		}
		if ( defined( 'AURA_BUILDER_META_ON_LEGACY' ) ) {
			$on = get_post_meta( $post_id, AURA_BUILDER_META_ON_LEGACY, true );
			if ( $on === '1' ) {
				return true;
			}
		}
		// Auto-enable when a saved document exists (new or legacy key).
		$raw = $this->read_raw_document( $post_id );
		return ! empty( $raw['nodes'] );
	}

	public function save( int $post_id, Document $document, bool $enable = true ): Document {
		$clean = DocumentSanitizer::sanitize( $document->to_array() );
		// Store as array (WP serializes); also works if string JSON needed later.
		update_post_meta( $post_id, AURA_BUILDER_META_DOC, $clean->to_array() );
		update_post_meta( $post_id, AURA_BUILDER_META_ON, $enable ? '1' : '0' );
		// Keep legacy key in sync so older tools / cache layers still see content.
		if ( defined( 'AURA_BUILDER_META_DOC_LEGACY' ) ) {
			update_post_meta( $post_id, AURA_BUILDER_META_DOC_LEGACY, $clean->to_array() );
		}
		if ( defined( 'AURA_BUILDER_META_ON_LEGACY' ) ) {
			update_post_meta( $post_id, AURA_BUILDER_META_ON_LEGACY, $enable ? '1' : '0' );
		}
		return $clean;
	}

	public function disable( int $post_id ): void {
		update_post_meta( $post_id, AURA_BUILDER_META_ON, '0' );
		if ( defined( 'AURA_BUILDER_META_ON_LEGACY' ) ) {
			update_post_meta( $post_id, AURA_BUILDER_META_ON_LEGACY, '0' );
		}
	}

	/**
	 * One-shot: copy every legacy document into the new meta key when new key is empty.
	 *
	 * @return array{migrated:int,skipped:int}
	 */
	public function migrate_legacy_meta(): array {
		global $wpdb;
		$migrated = 0;
		$skipped  = 0;
		if ( ! defined( 'AURA_BUILDER_META_DOC_LEGACY' ) ) {
			return array( 'migrated' => 0, 'skipped' => 0 );
		}
		// phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
		$ids = $wpdb->get_col(
			$wpdb->prepare(
				"SELECT DISTINCT post_id FROM {$wpdb->postmeta} WHERE meta_key = %s",
				AURA_BUILDER_META_DOC_LEGACY
			)
		);
		foreach ( (array) $ids as $pid ) {
			$pid = (int) $pid;
			if ( $pid < 1 ) {
				continue;
			}
			$new = $this->normalize_meta_value( get_post_meta( $pid, AURA_BUILDER_META_DOC, true ) );
			if ( ! empty( $new['nodes'] ) ) {
				++$skipped;
				continue;
			}
			$old = $this->normalize_meta_value( get_post_meta( $pid, AURA_BUILDER_META_DOC_LEGACY, true ) );
			if ( empty( $old['nodes'] ) ) {
				++$skipped;
				continue;
			}
			if ( empty( $old['rootId'] ) && ! empty( $old['root_id'] ) ) {
				$old['rootId'] = $old['root_id'];
			}
			update_post_meta( $pid, AURA_BUILDER_META_DOC, $old );
			update_post_meta( $pid, AURA_BUILDER_META_ON, '1' );
			++$migrated;
		}
		return array( 'migrated' => $migrated, 'skipped' => $skipped );
	}
}
