<?php
/**
 * Plugin settings storage and sanitization.
 *
 * @package MacaHold
 */

defined( 'ABSPATH' ) || exit;

/**
 * Settings handler.
 */
class Maca_Hold_Settings {

	/**
	 * Default settings.
	 *
	 * @return array<string, mixed>
	 */
	public static function get_defaults() {
		return array(
			'enabled'           => false,
			'title'             => __( 'Site Under Maintenance', 'maca-hold' ),
			'subtitle'          => '',
			'message'           => __( 'We are performing scheduled maintenance. Please check back soon.', 'maca-hold' ),
			'badge_text'        => '',
			'countdown_label'   => '',
			'footer_text'       => '',
			'logo_url'          => '',
			'logo_alt'          => '',
			'links'             => array(),
			'template'          => 'maintenance',
			'background_image'  => '',
			'background_color'  => '#1e1e2e',
			'text_color'        => '#f5f5f5',
			'accent_color'      => '#7c9cbf',
			'retry_after'       => 3600,
			'secret_token'      => '',
			'ip_whitelist'      => '',
			'schedule_enabled'  => false,
			'schedule_start'    => '',
			'schedule_end'      => '',
			'bypass_roles'      => array( 'administrator' ),
			'show_login_link'   => false,
			'login_link_label'  => '',
			'show_countdown'    => false,
			'setup_dismissed'   => false,
			'max_links'              => 20,
			'custom_background_url'  => '',
			'custom_background_label'=> '',
			'custom_css'             => '',
			'head_code'              => '',
			'favicon_url'            => '',
			'social_links'           => array(),
			'social_links_display'   => 'icons',
			'page_exception_mode'    => '',
			'page_exception_ids'     => array(),
		);
	}

	/**
	 * Get merged settings.
	 *
	 * @return array<string, mixed>
	 */
	public static function get() {
		$stored = get_option( MACA_HOLD_OPTION_KEY, array() );

		if ( ! is_array( $stored ) ) {
			$stored = array();
		}

		$merged = wp_parse_args( $stored, self::get_defaults() );
		$merged = self::maybe_migrate_legacy_pro_settings( $merged, $stored );

		return $merged;
	}

	/**
	 * Import settings from the legacy maca Hold Pro add-on option once.
	 *
	 * @param array<string, mixed> $merged Current merged settings.
	 * @param array<string, mixed> $stored Raw stored settings.
	 * @return array<string, mixed>
	 */
	private static function maybe_migrate_legacy_pro_settings( array $merged, array $stored ) {
		$legacy = get_option( 'maca_hold_pro_settings', null );

		if ( ! is_array( $legacy ) || empty( $legacy ) ) {
			return $merged;
		}

		$keys = array(
			'max_links',
			'custom_background_url',
			'custom_background_label',
			'custom_css',
			'head_code',
			'favicon_url',
			'social_links',
			'social_links_display',
			'page_exception_mode',
			'page_exception_ids',
		);

		foreach ( $keys as $key ) {
			if ( ! array_key_exists( $key, $stored ) && array_key_exists( $key, $legacy ) ) {
				$merged[ $key ] = $legacy[ $key ];
			}
		}

		return $merged;
	}

	/**
	 * Persist settings.
	 *
	 * @param array<string, mixed> $settings Settings.
	 * @return bool
	 */
	public static function update( array $settings ) {
		$sanitized = self::sanitize( $settings );
		$current   = self::get();

		if ( empty( $sanitized['secret_token'] ) && ! empty( $current['secret_token'] ) ) {
			$sanitized['secret_token'] = $current['secret_token'];
		}

		if ( empty( $sanitized['secret_token'] ) ) {
			$sanitized['secret_token'] = self::generate_secret_token();
		}

		return update_option( MACA_HOLD_OPTION_KEY, $sanitized );
	}

	/**
	 * Sanitize settings input.
	 *
	 * @param array<string, mixed> $input Raw input.
	 * @return array<string, mixed>
	 */
	public static function sanitize( array $input ) {
		$defaults = self::get_defaults();
		$output   = array();

		$output['enabled']          = ! empty( $input['enabled'] );
		$output['title']            = sanitize_text_field( $input['title'] ?? $defaults['title'] );
		$output['subtitle']         = sanitize_text_field( $input['subtitle'] ?? '' );
		$output['message']          = wp_kses_post( $input['message'] ?? $defaults['message'] );
		$output['badge_text']       = sanitize_text_field( $input['badge_text'] ?? '' );
		$output['countdown_label']  = sanitize_text_field( $input['countdown_label'] ?? '' );
		$output['footer_text']      = wp_kses_post( $input['footer_text'] ?? '' );
		$output['logo_url']         = esc_url_raw( $input['logo_url'] ?? '' );
		$output['logo_alt']         = sanitize_text_field( $input['logo_alt'] ?? '' );
		$output['links']            = self::sanitize_links( $input['links'] ?? array() );
		$output['template']         = self::sanitize_template( $input['template'] ?? '' );
		$output['background_image'] = Maca_Hold_Backgrounds::sanitize( $input['background_image'] ?? '' );
		$output['background_color'] = sanitize_hex_color( $input['background_color'] ?? $defaults['background_color'] ) ?: $defaults['background_color'];
		$output['text_color']       = sanitize_hex_color( $input['text_color'] ?? $defaults['text_color'] ) ?: $defaults['text_color'];
		$output['accent_color']     = sanitize_hex_color( $input['accent_color'] ?? $defaults['accent_color'] ) ?: $defaults['accent_color'];
		$output['retry_after']      = max( 0, absint( $input['retry_after'] ?? $defaults['retry_after'] ) );
		$output['secret_token']     = sanitize_key( $input['secret_token'] ?? '' );
		$output['ip_whitelist']     = self::sanitize_ip_list( $input['ip_whitelist'] ?? '' );
		$output['schedule_enabled'] = ! empty( $input['schedule_enabled'] );
		$output['schedule_start']   = Maca_Hold_Scheduler::sanitize_datetime( $input['schedule_start'] ?? '' );
		$output['schedule_end']     = Maca_Hold_Scheduler::sanitize_datetime( $input['schedule_end'] ?? '' );
		$output['show_countdown']   = ! empty( $input['show_countdown'] );
		$output['show_login_link']  = ! empty( $input['show_login_link'] );
		$output['login_link_label'] = sanitize_text_field( $input['login_link_label'] ?? '' );
		$output['setup_dismissed']  = ! empty( $input['setup_dismissed'] );

		$bypass_roles = $input['bypass_roles'] ?? $defaults['bypass_roles'];
		if ( ! is_array( $bypass_roles ) ) {
			$bypass_roles = array( 'administrator' );
		}

		$valid_roles           = array_keys( wp_roles()->roles );
		$output['bypass_roles'] = array_values(
			array_intersect(
				array_map( 'sanitize_key', $bypass_roles ),
				$valid_roles
			)
		);

		if ( empty( $output['bypass_roles'] ) ) {
			$output['bypass_roles'] = array( 'administrator' );
		}

		$head_code = (string) ( $input['head_code'] ?? '' );
		if ( ! current_user_can( 'unfiltered_html' ) ) {
			$head_code = wp_kses_post( $head_code );
		}

		$output['max_links']               = max( 5, absint( $input['max_links'] ?? $defaults['max_links'] ) );
		$output['custom_background_url']     = esc_url_raw( $input['custom_background_url'] ?? '' );
		$output['custom_background_label']   = sanitize_text_field( $input['custom_background_label'] ?? '' );
		$output['custom_css']                = self::sanitize_css( $input['custom_css'] ?? '' );
		$output['head_code']                 = $head_code;
		$output['favicon_url']               = esc_url_raw( $input['favicon_url'] ?? '' );
		$output['social_links']              = self::sanitize_social_links( $input['social_links'] ?? array() );
		$output['social_links_display']      = self::sanitize_social_links_display( $input['social_links_display'] ?? '' );
		$output['page_exception_mode']       = self::sanitize_page_exception_mode( $input['page_exception_mode'] ?? '' );
		$output['page_exception_ids']        = self::sanitize_page_exception_ids( $input['page_exception_ids'] ?? array() );

		return $output;
	}

	/**
	 * Build settings input from the admin save form.
	 *
	 * @param array<string, mixed> $post Unslashed POST data (nonce verified by caller).
	 * @return array<string, mixed>
	 */
	public static function from_post( array $post ) {
		$raw_bypass_roles = isset( $post['bypass_roles'] ) ? (array) $post['bypass_roles'] : array();

		return array(
			'enabled'          => ! empty( $post['enabled'] ),
			'title'            => sanitize_text_field( $post['title'] ?? '' ),
			'subtitle'         => sanitize_text_field( $post['subtitle'] ?? '' ),
			'message'          => wp_kses_post( $post['message'] ?? '' ),
			'badge_text'       => sanitize_text_field( $post['badge_text'] ?? '' ),
			'countdown_label'  => sanitize_text_field( $post['countdown_label'] ?? '' ),
			'footer_text'      => wp_kses_post( $post['footer_text'] ?? '' ),
			'logo_url'         => esc_url_raw( $post['logo_url'] ?? '' ),
			'logo_alt'         => sanitize_text_field( $post['logo_alt'] ?? '' ),
			'links'            => self::sanitize_links( isset( $post['links'] ) && is_array( $post['links'] ) ? $post['links'] : array() ),
			'template'         => sanitize_key( $post['template'] ?? 'maintenance' ),
			'background_image' => Maca_Hold_Backgrounds::sanitize( sanitize_text_field( $post['background_image'] ?? '' ) ),
			'background_color' => sanitize_hex_color( $post['background_color'] ?? '' ),
			'text_color'       => sanitize_hex_color( $post['text_color'] ?? '' ),
			'accent_color'     => sanitize_hex_color( $post['accent_color'] ?? '' ),
			'retry_after'      => absint( $post['retry_after'] ?? 3600 ),
			'secret_token'     => sanitize_key( $post['secret_token'] ?? '' ),
			'ip_whitelist'     => sanitize_textarea_field( $post['ip_whitelist'] ?? '' ),
			'schedule_enabled' => ! empty( $post['schedule_enabled'] ),
			'schedule_start'   => sanitize_text_field( $post['schedule_start'] ?? '' ),
			'schedule_end'     => sanitize_text_field( $post['schedule_end'] ?? '' ),
			'bypass_roles'     => array_map( 'sanitize_key', $raw_bypass_roles ),
			'show_login_link'  => ! empty( $post['show_login_link'] ),
			'login_link_label' => sanitize_text_field( $post['login_link_label'] ?? '' ),
			'show_countdown'   => ! empty( $post['show_countdown'] ),
			'setup_dismissed'  => ! empty( $post['setup_dismissed'] ),
		);
	}

	/**
	 * Available maintenance page templates.
	 *
	 * @return array<string, string> Template slug => label.
	 */
	public static function get_templates() {
		/**
		 * Filter maintenance page templates.
		 *
		 * @param array<string, string> $templates Template slug => label.
		 */
		return apply_filters(
			'maca_hold_templates',
			array(
				'maintenance' => __( 'Maintenance', 'maca-hold' ),
				'minimal'     => __( 'Minimal', 'maca-hold' ),
			)
		);
	}

	/**
	 * Sanitize a template slug.
	 *
	 * @param string $template Raw template slug.
	 * @return string
	 */
	public static function sanitize_template( $template ) {
		$template  = sanitize_key( $template );
		$templates = self::get_templates();

		if ( isset( $templates[ $template ] ) ) {
			return $template;
		}

		return 'maintenance';
	}

	/**
	 *
	 * @return bool
	 */
	public static function is_active() {
		$settings = self::get();

		if ( ! empty( $settings['schedule_enabled'] ) ) {
			return Maca_Hold_Scheduler::is_within_schedule( $settings );
		}

		return ! empty( $settings['enabled'] );
	}

	/**
	 * Generate a secret bypass token.
	 *
	 * @return string
	 */
	public static function generate_secret_token() {
		return wp_generate_password( 24, false, false );
	}

	/**
	 * Sanitize link rows for the maintenance page.
	 *
	 * @param mixed $links Raw link rows.
	 * @return array<int, array<string, mixed>>
	 */
	public static function sanitize_links( $links ) {
		if ( ! is_array( $links ) ) {
			return array();
		}

		/**
		 * Filter the maximum number of links on the maintenance page.
		 *
		 * @param int $max_links Maximum links.
		 */
		$max_links = max( 1, (int) apply_filters( 'maca_hold_max_links', 5 ) );
		$output    = array();

		foreach ( array_slice( $links, 0, $max_links ) as $link ) {
			if ( ! is_array( $link ) ) {
				continue;
			}

			$label = sanitize_text_field( $link['label'] ?? '' );
			$url   = esc_url_raw( $link['url'] ?? '' );

			if ( '' === $label || '' === $url ) {
				continue;
			}

			$output[] = array(
				'label'   => $label,
				'url'     => $url,
				'new_tab' => ! empty( $link['new_tab'] ),
			);
		}

		return $output;
	}

	/**
	 * Resolve badge text for the maintenance page.
	 *
	 * @param array<string, mixed> $settings Plugin settings.
	 * @param bool                 $has_bg_image Whether a background image is active.
	 * @return string Empty string when no badge should be shown.
	 */
	public static function get_badge_text( array $settings, $has_bg_image ) {
		$badge_text = trim( (string) ( $settings['badge_text'] ?? '' ) );

		if ( '' !== $badge_text ) {
			return $badge_text;
		}

		if ( $has_bg_image ) {
			return '';
		}

		return __( 'Under maintenance', 'maca-hold' );
	}

	/**
	 * Resolve countdown label for the maintenance page.
	 *
	 * @param array<string, mixed> $settings Plugin settings.
	 * @return string
	 */
	public static function get_countdown_label( array $settings ) {
		$label = trim( (string) ( $settings['countdown_label'] ?? '' ) );

		if ( '' !== $label ) {
			return $label;
		}

		return __( 'Back soon in', 'maca-hold' );
	}

	/**
	 * Sanitize IP whitelist text.
	 *
	 * @param string $value Raw list.
	 * @return string
	 */
	private static function sanitize_ip_list( $value ) {
		$lines = preg_split( '/[\r\n,]+/', (string) $value );
		$ips   = array();

		foreach ( $lines as $line ) {
			$ip = trim( $line );
			if ( '' === $ip ) {
				continue;
			}

			if ( filter_var( $ip, FILTER_VALIDATE_IP ) ) {
				$ips[] = $ip;
			}
		}

		return implode( "\n", array_unique( $ips ) );
	}

	/**
	 * Build advanced settings from the admin advanced tab form.
	 *
	 * @param array<string, mixed> $post Unslashed POST data (nonce verified by caller).
	 * @return array<string, mixed>
	 */
	public static function from_advanced_post( array $post ) {
		return array(
			'max_links'              => absint( $post['max_links'] ?? 20 ),
			'custom_background_url'  => esc_url_raw( $post['custom_background_url'] ?? '' ),
			'custom_background_label'=> sanitize_text_field( $post['custom_background_label'] ?? '' ),
			'custom_css'             => $post['custom_css'] ?? '',
			'head_code'              => $post['head_code'] ?? '',
			'favicon_url'            => esc_url_raw( $post['favicon_url'] ?? '' ),
			'social_links'           => isset( $post['social_links'] ) && is_array( $post['social_links'] ) ? $post['social_links'] : array(),
			'social_links_display'   => sanitize_key( $post['social_links_display'] ?? 'icons' ),
			'page_exception_mode'    => sanitize_key( $post['page_exception_mode'] ?? '' ),
			'page_exception_ids'     => isset( $post['page_exception_ids'] ) ? (array) $post['page_exception_ids'] : array(),
		);
	}

	/**
	 * @param mixed $css Raw CSS.
	 * @return string
	 */
	private static function sanitize_css( $css ) {
		$css = wp_strip_all_tags( (string) wp_unslash( $css ) );
		$css = str_replace( array( '</style', '<style' ), '', $css );

		return trim( $css );
	}

	/**
	 * @param mixed $links Raw link rows.
	 * @return array<int, array<string, mixed>>
	 */
	private static function sanitize_social_links( $links ) {
		if ( ! is_array( $links ) ) {
			return array();
		}

		$output = array();

		foreach ( array_slice( $links, 0, 6 ) as $link ) {
			if ( ! is_array( $link ) ) {
				continue;
			}

			$network = sanitize_key( $link['network'] ?? 'custom' );
			if ( ! Maca_Hold_Social_Networks::is_valid( $network ) ) {
				$network = 'custom';
			}

			$url = esc_url_raw( $link['url'] ?? '' );
			if ( '' === $url ) {
				continue;
			}

			$label = sanitize_text_field( $link['label'] ?? '' );
			if ( '' === $label ) {
				$label = Maca_Hold_Social_Networks::get_label( $network );
			}

			$output[] = array(
				'network'  => $network,
				'label'    => $label,
				'url'      => $url,
				'icon_url' => esc_url_raw( $link['icon_url'] ?? '' ),
				'new_tab'  => ! empty( $link['new_tab'] ),
			);
		}

		return $output;
	}

	/**
	 * @param mixed $display Raw display mode.
	 * @return string
	 */
	private static function sanitize_social_links_display( $display ) {
		$display = sanitize_key( (string) $display );

		if ( in_array( $display, array( 'icons', 'icons_text' ), true ) ) {
			return $display;
		}

		return 'icons';
	}

	/**
	 * @param mixed $mode Raw mode.
	 * @return string
	 */
	private static function sanitize_page_exception_mode( $mode ) {
		$mode = sanitize_key( (string) $mode );

		if ( in_array( $mode, array( 'open', 'closed' ), true ) ) {
			return $mode;
		}

		return '';
	}

	/**
	 * @param mixed $page_ids Raw page IDs.
	 * @return array<int, int>
	 */
	private static function sanitize_page_exception_ids( $page_ids ) {
		if ( ! is_array( $page_ids ) ) {
			return array();
		}

		$output = array();

		foreach ( $page_ids as $page_id ) {
			$page_id = absint( $page_id );
			if ( $page_id < 1 || 'page' !== get_post_type( $page_id ) ) {
				continue;
			}

			$output[] = $page_id;
		}

		return array_values( array_unique( $output ) );
	}
}
