<?php
/**
 * Settings access and sanitization.
 *
 * @package 404Zen
 */

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

class LGBF_Settings {

	const OPTION_KEY = 'lgbf_settings';

	/**
	 * Available scan frequencies.
	 *
	 * @var array
	 */
	public static $frequencies = array( 'hourly', 'twicedaily', 'daily', 'weekly' );

	/**
	 * @return array Default settings.
	 */
	public static function defaults() {
		return array(
			'scan_frequency'     => 'daily',
			'batch_size'         => 50,
			'check_images'       => 1,
			'check_external'     => 1,
			'check_internal'     => 1,
			'exclude_post_types' => array(),
			'exclude_urls'       => array(),
			'digest_enabled'     => 1,
			'digest_recipient'   => '',
			'updates_optin'      => 0,
			'request_timeout'    => 10,
			'max_load'           => 0, // 0 = auto (number of CPU cores).
		);
	}

	/**
	 * Returns all settings merged with defaults.
	 *
	 * @return array
	 */
	public static function all() {
		$saved = get_option( self::OPTION_KEY, array() );
		if ( ! is_array( $saved ) ) {
			$saved = array();
		}

		$settings = wp_parse_args( $saved, self::defaults() );

		return $settings;
	}

	/**
	 * Returns a single setting.
	 *
	 * @param string $key Setting key.
	 * @return mixed
	 */
	public static function get( $key ) {
		$settings = self::all();

		return isset( $settings[ $key ] ) ? $settings[ $key ] : null;
	}

	/**
	 * Sanitizes settings submitted from the settings screen.
	 *
	 * @param array $input Raw input.
	 * @return array Clean settings.
	 */
	public static function sanitize( $input ) {
		$defaults = self::defaults();
		$clean    = array();

		if ( ! is_array( $input ) ) {
			return $defaults;
		}

		$frequency = isset( $input['scan_frequency'] ) ? sanitize_key( $input['scan_frequency'] ) : 'daily';
		if ( ! in_array( $frequency, self::$frequencies, true ) ) {
			$frequency = 'daily';
		}
		$clean['scan_frequency'] = $frequency;

		$batch_size          = isset( $input['batch_size'] ) ? absint( $input['batch_size'] ) : $defaults['batch_size'];
		$clean['batch_size'] = max( 10, min( 200, $batch_size ) );

		$clean['check_images']   = empty( $input['check_images'] ) ? 0 : 1;
		$clean['check_external'] = empty( $input['check_external'] ) ? 0 : 1;
		$clean['check_internal'] = empty( $input['check_internal'] ) ? 0 : 1;
		$clean['digest_enabled'] = empty( $input['digest_enabled'] ) ? 0 : 1;

		$recipient                 = isset( $input['digest_recipient'] ) ? sanitize_email( $input['digest_recipient'] ) : '';
		$clean['digest_recipient'] = $recipient;

		// Product-updates co-consent: explicit, unchecked by default. Record
		// the opt-in only on the transition from unchecked to checked.
		$clean['updates_optin'] = empty( $input['updates_optin'] ) ? 0 : 1;
		$previous               = get_option( self::OPTION_KEY, array() );
		$was_opted              = is_array( $previous ) && ! empty( $previous['updates_optin'] );
		if ( $clean['updates_optin'] && ! $was_opted && class_exists( 'LGBF_Optin' ) ) {
			$optin_email = $recipient ? $recipient : get_option( 'admin_email' );
			LGBF_Optin::record( $optin_email, 'digest_settings' );
		}

		$timeout                  = isset( $input['request_timeout'] ) ? absint( $input['request_timeout'] ) : $defaults['request_timeout'];
		$clean['request_timeout'] = max( 3, min( 30, $timeout ) );

		$clean['max_load'] = isset( $input['max_load'] ) ? min( 64, absint( $input['max_load'] ) ) : 0;

		$clean['exclude_post_types'] = array();
		if ( ! empty( $input['exclude_post_types'] ) && is_array( $input['exclude_post_types'] ) ) {
			foreach ( $input['exclude_post_types'] as $post_type ) {
				$post_type = sanitize_key( $post_type );
				if ( $post_type ) {
					$clean['exclude_post_types'][] = $post_type;
				}
			}
		}

		$clean['exclude_urls'] = array();
		if ( isset( $input['exclude_urls'] ) ) {
			$raw_patterns = is_array( $input['exclude_urls'] )
				? $input['exclude_urls']
				: explode( "\n", (string) $input['exclude_urls'] );
			foreach ( $raw_patterns as $pattern ) {
				$pattern = trim( sanitize_text_field( $pattern ) );
				if ( '' !== $pattern ) {
					$clean['exclude_urls'][] = $pattern;
				}
			}
			$clean['exclude_urls'] = array_slice( array_unique( $clean['exclude_urls'] ), 0, 200 );
		}

		return $clean;
	}

	/**
	 * Post types eligible for scanning (public, minus exclusions).
	 *
	 * @return string[]
	 */
	public static function scannable_post_types() {
		$post_types = get_post_types( array( 'public' => true ), 'names' );
		unset( $post_types['attachment'] );

		$excluded = self::get( 'exclude_post_types' );
		if ( is_array( $excluded ) ) {
			$post_types = array_diff( $post_types, $excluded );
		}

		return array_values( $post_types );
	}

	/**
	 * Digest recipient with fallback to the site admin email.
	 *
	 * @return string
	 */
	public static function digest_recipient() {
		$recipient = self::get( 'digest_recipient' );

		return $recipient ? $recipient : get_option( 'admin_email' );
	}
}
