<?php
/**
 * IAB TCF v2.2 integration (CMP API + vendor list mirror).
 *
 * @package BlaminhorEssentials
 *
 * NOTE: This module ships an auto-declared, *non-certified* CMP. It implements
 * the technical surface (cookie `euconsent-v2`, `window.__tcfapi` runtime) but
 * does not have an official CMP ID issued by IAB Europe. Sites that require
 * strict TCF certification (high-end ad publishers) should either acquire
 * certification themselves and override the CMP ID via the filter exposed
 * below, or use a different CMP.
 */

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

/**
 * Minimal server-side TCF adapter: stores the latest TC string in the consent
 * log, exposes admin metadata for the runtime, and handles the vendor list
 * mirror cron.
 */
class Blaminhor_Essentials_Cookies_TCF_Adapter {

	const VENDOR_LIST_URL     = 'https://vendor-list.consensu.org/v3/vendor-list.json';
	const VENDOR_LIST_OPTION  = 'blaminhor_essentials_cookies_vendor_list_version';
	const CRON_HOOK           = 'blaminhor_essentials_cookies_tcf_vendor_list_refresh';
	const SELF_CMP_ID         = 999; // Placeholder while we don't have an official one.
	const SELF_CMP_VERSION    = 1;
	const POLICY_VERSION      = 4;

	/**
	 * Get a public-safe descriptor of the CMP for the JS runtime.
	 *
	 * @return array
	 */
	public function get_runtime_descriptor() {
		return apply_filters(
			'blaminhor_cookies_tcf_runtime_descriptor',
			array(
				'cmpId'             => (int) self::SELF_CMP_ID,
				'cmpVersion'        => (int) self::SELF_CMP_VERSION,
				'policyVersion'     => (int) self::POLICY_VERSION,
				'vendorListVersion' => (int) get_option( self::VENDOR_LIST_OPTION, 0 ),
				'isServiceSpecific' => true,
			)
		);
	}

	/**
	 * Schedule the vendor list refresh.
	 */
	public function schedule_vendor_list_refresh() {
		if ( ! wp_next_scheduled( self::CRON_HOOK ) ) {
			wp_schedule_event( time() + HOUR_IN_SECONDS, 'daily', self::CRON_HOOK );
		}
		add_action( self::CRON_HOOK, array( $this, 'refresh_vendor_list' ) );
	}

	/**
	 * Unschedule the vendor list cron (called on deactivation).
	 */
	public function unschedule_vendor_list_refresh() {
		$ts = wp_next_scheduled( self::CRON_HOOK );
		if ( $ts ) {
			wp_unschedule_event( $ts, self::CRON_HOOK );
		}
	}

	/**
	 * Fetch the vendor list, cache it locally for offline fallback, bump version.
	 */
	public function refresh_vendor_list() {
		$response = wp_remote_get(
			self::VENDOR_LIST_URL,
			array(
				'timeout'    => 20,
				'user-agent' => 'BlaminhorEssentials/' . BLAMINHOR_ESSENTIALS_VERSION,
			)
		);
		if ( is_wp_error( $response ) || 200 !== (int) wp_remote_retrieve_response_code( $response ) ) {
			return;
		}
		$body = wp_remote_retrieve_body( $response );
		$data = json_decode( $body, true );
		if ( ! is_array( $data ) || empty( $data['vendorListVersion'] ) ) {
			return;
		}

		$path = $this->get_local_path();
		wp_mkdir_p( dirname( $path ) );

		global $wp_filesystem;
		if ( empty( $wp_filesystem ) ) {
			require_once ABSPATH . 'wp-admin/includes/file.php';
			WP_Filesystem();
		}
		if ( $wp_filesystem ) {
			$wp_filesystem->put_contents( $path, $body, FS_CHMOD_FILE );
		}

		update_option( self::VENDOR_LIST_OPTION, (int) $data['vendorListVersion'], false );
	}

	/**
	 * Path of the locally mirrored vendor list.
	 *
	 * @return string
	 */
	public function get_local_path() {
		$upload = wp_upload_dir();
		return trailingslashit( $upload['basedir'] ) . 'blaminhor-essentials/tcf/vendor-list.json';
	}

	/**
	 * @return bool Whether a local mirror exists.
	 */
	public function has_local_mirror() {
		return is_readable( $this->get_local_path() );
	}
}
