<?php
namespace ActiriseAdmin\Includes;

if ( ! defined( 'ABSPATH' ) ) {
	exit; // Exit if accessed directly
}

use Actirise\Includes\Api;
use Actirise\Includes\Options;

/**
 * Health Check functionality
 *
 * Checks configuration status for various features and returns issues
 *
 * @link       https://actirise.com
 * @since      4.0.0
 * @package    actirise
 * @subpackage actirise/admin/includes
 * @author     actirise <wordpress@actirise.com>
 */
final class HealthCheck {
	/**
	 * Api class
	 *
	 * @since    4.0.0
	 * @access   private
	 * @var      Api    $api    Api class.
	 */
	private $api;

	/**
	 * CMP vendors cache
	 *
	 * @since 4.0.0
	 * @var array<mixed>|null
	 */
	private $cmp_vendors_cache = null;

	/**
	 * Initialize the class
	 *
	 * @since 4.0.0
	 */
	public function __construct() {
		$this->api = new Api();
	}

	/**
	 * Get all health check issues
	 *
	 * @since 4.0.0
	 * @return array<array<string, mixed>>
	 */
	public function get_issues() {
		$issues = array();

		// Check presized divs (Core Web Vitals)
		$core_web_vitals_issue = $this->check_core_web_vitals();
		if ( $core_web_vitals_issue ) {
			$issues[] = $core_web_vitals_issue;
		}

		// Check Ads.txt
		$adstxt_issue = $this->check_adstxt();
		if ( $adstxt_issue ) {
			$issues[] = $adstxt_issue;
		}

		// Check Ad Formats
		$ad_formats_issue = $this->check_ad_formats();
		if ( $ad_formats_issue ) {
			$issues[] = $ad_formats_issue;
		}

		// Check CMP vendors
		$cmp_issue = $this->check_cmp();
		if ( $cmp_issue ) {
			$issues[] = $cmp_issue;
		}

		// Check hosted ads.txt redirect
		$ads_txt_redirect_issue = $this->check_hosted_adstxt_redirect();
		if ( $ads_txt_redirect_issue ) {
			$issues[] = $ads_txt_redirect_issue;
		}

		// Suggest migration to hosted ads.txt
		$ads_txt_migration_issue = $this->check_adstxt_migration();
		if ( $ads_txt_migration_issue ) {
			$issues[] = $ads_txt_migration_issue;
		}

		// Check optimization checklist
		$optimization_issue = $this->check_optimization_checklist();
		if ( $optimization_issue ) {
			$issues[] = $optimization_issue;
		}

		return $issues;
	}

	/**
	 * Check Core Web Vitals / Presized Divs
	 *
	 * Checks if all available presized divs are activated.
	 * Returns an issue if:
	 * - Feature is disabled, OR
	 * - Feature is enabled but not all presized divs are activated
	 *
	 * @since 4.0.0
	 * @return array<string, mixed>|null
	 */
	public function check_core_web_vitals() {
		$presized_div_active = Options::get( 'presizeddiv-active', false );

		// Get available presized divs from Actirise
		/** @var array<array<string, mixed>> $available_divs */
		$available_divs = Options::get( 'presizeddiv-actirise', array() );

		// If no presized divs available, no issue
		if ( empty( $available_divs ) ) {
			return null;
		}

		// If feature is disabled, all divs are inactive
		if ( ! $presized_div_active ) {
			return array(
				'type'  => 'core_web_vitals',
				'count' => count( $available_divs ),
			);
		}

		// Feature is enabled, check selected/activated presized divs
		/** @var array<array<string, mixed>> $selected_divs */
		$selected_divs = Options::get( 'presizeddiv-selected', array() );

		// Count inactive presized divs by comparing available vs selected
		$inactive_count = 0;

		foreach ( $available_divs as $available_div ) {
			$slot_name = isset( $available_div['slotName'] ) ? $available_div['slotName'] : '';
			if ( empty( $slot_name ) ) {
				continue;
			}

			// Check if this div is in selected and active
			$is_active = false;
			foreach ( $selected_divs as $selected_div ) {
				if ( isset( $selected_div['slotName'] ) && $selected_div['slotName'] === $slot_name ) {
					$is_active = isset( $selected_div['active'] ) && $selected_div['active'] === true;
					break;
				}
			}

			if ( ! $is_active ) {
				++$inactive_count;
			}
		}

		if ( $inactive_count > 0 ) {
			return array(
				'type'  => 'core_web_vitals',
				'count' => $inactive_count,
			);
		}

		return null;
	}

	/**
	 * Check Ads.txt configuration
	 *
	 * @since 4.0.0
	 * @return array<string, mixed>|null
	 */
	public function check_adstxt() {
		if ( Options::get( 'adstxt-active', false ) === false && Options::get( 'adstxt-update', false ) === true ) {
			$missing_count   = Options::get( 'adstxt-missing-count', 0 );
			$blacklist_count = Options::get( 'adstxt-blacklist-count', 0 );

			return array(
				'type'      => 'adstxt',
				'missing'   => $missing_count,
				'blacklist' => $blacklist_count,
			);
		}

		return null;
	}

	/**
	 * Check Ad Formats configuration
	 * Premium users do not control ad placements, so this check is irrelevant for them.
	 *
	 * @since 4.0.0
	 * @return array<string, mixed>|null
	 */
	public function check_ad_formats() {
		if ( Options::get( 'contract-type' ) === 'premium' ) {
			return null;
		}

		$xpath_failed_active_config = Options::get( 'xpath_failed_active_config', 0 );

		// Handle boolean true case (should be treated as 1)
		if ( true === $xpath_failed_active_config ) {
			$xpath_failed_active_config = 1;
		}

		// Convert to int if it's numeric
		if ( is_numeric( $xpath_failed_active_config ) ) {
			$xpath_failed_active_config = (int) $xpath_failed_active_config;
		}

		if ( $xpath_failed_active_config > 0 ) {
			return array(
				'type'  => 'ad_formats',
				'count' => $xpath_failed_active_config,
			);
		}

		return null;
	}

	/**
	 * Check CMP vendors configuration
	 *
	 * @since 4.0.0
	 * @return array<string, mixed>|null
	 */
	public function check_cmp() {
		// Only check if using own CMP (fastCMP disabled)
		if ( Options::get( 'fastcmp-enabled', false ) !== false ) {
			return null;
		}

		// Get current vendors
		$vendors = $this->get_cmp_vendors();

		if ( empty( $vendors ) ) {
			return null;
		}

		// Get saved snapshot
		$saved_vendors = Options::get( 'cmp_vendors_snapshot', array() );

		if ( ! is_array( $saved_vendors ) || empty( $saved_vendors ) ) {
			// No snapshot saved, consider it as changed
			return array(
				'type' => 'cmp',
			);
		}

		// Extract vendor IDs from current vendors
		$current_vendor_ids = array_map(
			function ( $vendor ) {
				if ( ! is_array( $vendor ) || ! isset( $vendor['id'] ) ) {
					return null;
				}
				return is_string( $vendor['id'] ) || is_int( $vendor['id'] )
					? (int) $vendor['id']
					: null;
			},
			$vendors
		);

		// Remove null values
		$current_vendor_ids = array_values( array_filter( $current_vendor_ids ) );

		// Sort for comparison
		sort( $current_vendor_ids );
		sort( $saved_vendors );

		// Compare
		if ( $saved_vendors !== $current_vendor_ids ) {
			return array(
				'type' => 'cmp',
			);
		}

		return null;
	}

	/**
	 * Get CMP vendors from API
	 *
	 * @since 4.0.0
	 * @return array<mixed>
	 */
	private function get_cmp_vendors() {
		// Return cached value if already fetched
		if ( $this->cmp_vendors_cache !== null ) {
			return $this->cmp_vendors_cache;
		}

		/** @var string $token */
		$token    = Options::get( 'settings-analytics-token', '' );
		$response = $this->api->get( 'api', 'cmp_vendors', array(), $token );

		if ( is_wp_error( $response ) || ! is_array( $response ) || empty( $response ) ) {
			$this->cmp_vendors_cache = array();
			return array();
		}

		$this->cmp_vendors_cache = $response;
		return $response;
	}

	/**
	 * Check hosted ads.txt redirect
	 *
	 * Returns an issue if hosted ads.txt is enabled but the redirect
	 * is obstructed by a local file or a conflicting third-party rule.
	 *
	 * @since 3.4.2
	 * @return array<string, mixed>|null
	 */
	public function check_hosted_adstxt_redirect() {
		$hosted_enabled = Options::get( 'hosted-adstxt-enabled', false );

		if ( ! $hosted_enabled ) {
			return null;
		}

		$redirect_error = Options::get( 'hosted-adstxt-redirect-error', false );

		if ( empty( $redirect_error ) || ! is_array( $redirect_error ) ) {
			return null;
		}

		$error_type = isset( $redirect_error['error_type'] ) ? $redirect_error['error_type'] : '';

		if ( 'file_exists' === $error_type || 'third_party' === $error_type ) {
			return array(
				'type'       => 'ads_txt_redirect',
				'error_type' => $error_type,
			);
		}

		return null;
	}

	/**
	 * Check if publisher should migrate to hosted ads.txt
	 *
	 * Returns an issue if ads.txt is active but not using hosted mode,
	 * suggesting the publisher migrate for automatic seller updates.
	 *
	 * @since 3.4.2
	 * @return array<string, mixed>|null
	 */
	public function check_adstxt_migration() {
		$hosted_enabled = Options::get( 'hosted-adstxt-enabled', false );

		if ( $hosted_enabled ) {
			return null;
		}

		// Check if hosted ads.txt feature is available for this website
		$website_settings        = Options::get( 'website-settings', array() );
		$hosted_adstxt_available = is_array( $website_settings )
			&& isset( $website_settings['hosted_adstxt'] )
			&& $website_settings['hosted_adstxt'];

		if ( $hosted_adstxt_available ) {
			return array(
				'type' => 'ads_txt_migration',
			);
		}

		return null;
	}

	/**
	 * Check if all optimization checklist items are completed.
	 *
	 * Returns an issue if any of the 7 checklist items is incomplete:
	 * - Hosted ads.txt enabled
	 * - Cache exclusion marked as done (manual)
	 * - FastCMP enabled
	 * - Corner ad format enabled
	 * - Rewards ad format enabled
	 * - Pre-sized divs all enabled
	 * - Editorial best practices marked as done (manual)
	 *
	 * @since 4.1.0
	 * @return array<string, mixed>|null
	 */
	private function check_optimization_checklist() {
		// Only relevant for essential contract types
		if ( Options::get( 'contract-type' ) !== 'essential' ) {
			return null;
		}

		// 1. Hosted ads.txt
		$hosted_adstxt = Options::get( 'hosted-adstxt-enabled', false );
		if ( ! $hosted_adstxt ) {
			return array( 'type' => 'optimization_checklist' );
		}

		// 2. Cache exclusion (manual)
		$manual_steps = Options::get( 'optimization-checklist-manual', array() );
		if ( ! is_array( $manual_steps ) || empty( $manual_steps['cache_exclusion'] ) ) {
			return array( 'type' => 'optimization_checklist' );
		}

		// 3. FastCMP
		$fastcmp_enabled = Options::get( 'fastcmp-enabled', false );
		if ( ! $fastcmp_enabled ) {
			return array( 'type' => 'optimization_checklist' );
		}

		// 4 & 5. Corner and Rewards ad formats (keyed by slug name with device info)
		$enabled_slugs = Options::get( 'ad-format-enabled-slugs', array() );
		if ( ! is_array( $enabled_slugs ) ) {
			return array( 'type' => 'optimization_checklist' );
		}
		foreach ( array( 'corner', 'rewards' ) as $slug ) {
			if ( ! isset( $enabled_slugs[ $slug ] ) || ! is_array( $enabled_slugs[ $slug ] ) ) {
				return array( 'type' => 'optimization_checklist' );
			}
			if ( empty( $enabled_slugs[ $slug ]['desktop'] ) || empty( $enabled_slugs[ $slug ]['mobile'] ) ) {
				return array( 'type' => 'optimization_checklist' );
			}
		}

		// 6. Pre-sized divs: feature enabled AND all selected slots active
		$presized_active = Options::get( 'presizeddiv-active', false );
		if ( ! $presized_active ) {
			return array( 'type' => 'optimization_checklist' );
		}

		$presized_selected = Options::get( 'presizeddiv-selected', array() );
		if ( is_array( $presized_selected ) ) {
			foreach ( $presized_selected as $slot ) {
				if ( isset( $slot['active'] ) && ! $slot['active'] ) {
					return array( 'type' => 'optimization_checklist' );
				}
			}
		}

		// 7. Editorial best practices (manual)
		if ( empty( $manual_steps['editorial_best_practices'] ) ) {
			return array( 'type' => 'optimization_checklist' );
		}

		return null;
	}
}
