<?php
/**
 * Issue ignores. Lets the user say "this is fine" - per page or sitewide -
 * without losing anything: ignored issues stay stored (flagged in the row's
 * issues JSON, shown greyed in the details popup) but stop counting toward
 * issue_count, the Issues tab, summaries, and reports.
 *
 * Toggling takes effect instantly by rewriting the affected stored rows;
 * scans re-apply the flags at save time so ignores persist across rescans.
 *
 * Storage: one non-autoloaded option with both scopes
 * (same option-not-meta reasoning as the exclude list - enumerable in one
 * read, no meta_query):
 *
 *   ssaa_ignored_issues = array(
 *       'site'  => array( 'missing_canonical', ... ),
 *       'posts' => array( 123 => array( 'noindex', ... ), ... ),
 *   )
 *
 * @package search-social-appearance-audit
 */

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

class SSAA_Ignores {

	const OPTION = 'ssaa_ignored_issues';

	public static function init() {
		// No hooks needed.
	}

	/**
	 * Full ignore lists, normalised.
	 *
	 * @return array { site: string[], posts: array<int,string[]> }
	 */
	public static function get() {
		$raw = (array) get_option( self::OPTION, array() );

		$site = array();
		if ( isset( $raw['site'] ) ) {
			$site = array_values( array_unique( array_filter( array_map( 'sanitize_key', (array) $raw['site'] ) ) ) );
		}

		$posts = array();
		if ( isset( $raw['posts'] ) && is_array( $raw['posts'] ) ) {
			foreach ( $raw['posts'] as $post_id => $codes ) {
				$post_id = absint( $post_id );
				$codes   = array_values( array_unique( array_filter( array_map( 'sanitize_key', (array) $codes ) ) ) );
				if ( $post_id && $codes ) {
					$posts[ $post_id ] = $codes;
				}
			}
		}

		return array(
			'site'  => $site,
			'posts' => $posts,
		);
	}

	/**
	 * The ignore scope applying to an issue code on a post.
	 *
	 * @param string $code    Issue code.
	 * @param int    $post_id Post ID.
	 * @return string '' (not ignored), 'site', or 'page'.
	 */
	public static function scope_for( $code, $post_id ) {
		$lists = self::get();

		if ( in_array( $code, $lists['site'], true ) ) {
			return 'site';
		}
		if ( isset( $lists['posts'][ absint( $post_id ) ] ) && in_array( $code, $lists['posts'][ absint( $post_id ) ], true ) ) {
			return 'page';
		}
		return '';
	}

	/**
	 * Whether anything is ignored at all (drives the Ignored tab).
	 *
	 * @return bool
	 */
	public static function has_any() {
		$lists = self::get();
		return ! empty( $lists['site'] ) || ! empty( $lists['posts'] );
	}

	/**
	 * Add or remove an ignore, then rewrite the affected stored rows so the
	 * change takes effect immediately (no rescan needed).
	 *
	 * @param string $scope   'site' or 'page'.
	 * @param string $code    Issue code.
	 * @param int    $post_id Post ID (required for scope 'page').
	 * @param bool   $remove  True to un-ignore.
	 * @return bool
	 */
	public static function toggle( $scope, $code, $post_id = 0, $remove = false ) {
		$code    = sanitize_key( $code );
		$post_id = absint( $post_id );

		if ( '' === $code || ( 'page' === $scope && ! $post_id ) ) {
			return false;
		}

		$lists = self::get();

		if ( 'site' === $scope ) {
			if ( $remove ) {
				$lists['site'] = array_values( array_diff( $lists['site'], array( $code ) ) );
			} elseif ( ! in_array( $code, $lists['site'], true ) ) {
				$lists['site'][] = $code;
			}
		} elseif ( 'page' === $scope ) {
			$current = isset( $lists['posts'][ $post_id ] ) ? $lists['posts'][ $post_id ] : array();
			if ( $remove ) {
				$current = array_values( array_diff( $current, array( $code ) ) );
			} elseif ( ! in_array( $code, $current, true ) ) {
				$current[] = $code;
			}
			if ( $current ) {
				$lists['posts'][ $post_id ] = $current;
			} else {
				unset( $lists['posts'][ $post_id ] );
			}
		} else {
			return false;
		}

		update_option( self::OPTION, $lists, false );

		// Instant effect: reflag the rows this change touches.
		if ( 'site' === $scope ) {
			SSAA_Results::reflag_rows_with_code( $code );
		} else {
			SSAA_Results::reflag( $post_id );
		}
		SSAA_Results::refresh_summary();

		SSAA_Logger::info( $remove ? 'issue_unignored' : 'issue_ignored', array(
			'scope'   => $scope,
			'code'    => $code,
			'post_id' => $post_id,
		) );

		return true;
	}
}
