<?php
/**
 * Trait JsonDecodeTrait
 *
 * Provides shared logic for handling string|array data in jsonUnserialize.
 *
 * Should generally be used together with Northmill_Online_Shared\Interfaces\JsonUnserializable
 *
 * @package northmill-online-shared
 */

declare(strict_types=1);

namespace Northmill_Online_Shared\Traits;

use Northmill_Online_Shared\Abstract_Shared_Base;
use Northmill_Online_Shared\Modules\Loggers\Log_Level_Enum;

defined( 'ABSPATH' ) || exit;

/**
 * Trait JsonDecodeTrait
 *
 * Provides shared logic for handling string|array data in jsonUnserialize.
 *
 * @used Northmill Sync
 */
trait Json_Decode_Trait {
	/**
	 * Decodes the provided data if it is a JSON string.
	 *
	 * @param string|array $data JSON string or an already associative array.
	 * @param array        $required_keys The keys that must be present in the data.
	 *
	 * @return array|null Decoded array, or null if the data is not a valid JSON string.
	 *
	 * @used Northmill Sync
	 */
	final protected static function decode_json_data( string|array $data, array $required_keys = array() ): ?array {
		if ( is_string( $data ) ) {
			if ( '' === trim( $data ) ) {
				return null;
			}

			$string = $data;
			$data   = json_decode( $data, true );

			if (
				null === $data &&
				json_last_error() !== JSON_ERROR_NONE
			) {
				Abstract_Shared_Base::base_instance()->logger->log(
					'json-decode',
					'Invalid JSON provided',
					array(
						'error'  => json_last_error_msg(),
						'string' => $string,
					),
					Log_Level_Enum::ERROR
				);
				return null;
			}
		}

		if ( ! empty( $required_keys ) ) {
			return self::has_required_data( $data, $required_keys ) ? $data : null;
		}

		return $data;
	}

	/**
	 * Checks if the provided data is an array and contains all required keys.
	 *
	 * @param mixed $data The data to check.
	 * @param array $required_keys The keys that must be present in the data.
	 *
	 * @return bool True if the data is an array and contains all required keys, false otherwise.
	 *
	 * @used Northmill Sync
	 */
	protected static function has_required_data( mixed $data, array $required_keys = array() ): bool {
		if ( ! is_array( $data ) ) {
			return false;
		}

		foreach ( $required_keys as $required_key ) {
			if ( ! array_key_exists( $required_key, $data ) ) {
				return false;
			}
		}

		return true;
	}
}
