<?php
/**
 * Button configuration defaults and sanitization.
 *
 * @package Rsmspark_Content_Widgets
 */

defined( 'ABSPATH' ) || exit;

/**
 * Rsmspark_Buttons_Config
 */
class Rsmspark_Buttons_Config {

	const META_KEY = '_rsmspark_button_config';

	const CPT = 'rsmspark_button';

	/**
	 * @return array<string, mixed>
	 */
	public static function defaults() {
		$defaults = self::base_defaults();

		if ( class_exists( 'Rsmspark_Buttons_Settings', false ) ) {
			$defaults = wp_parse_args( Rsmspark_Buttons_Settings::get_new_button_defaults(), $defaults );
		}

		return apply_filters( 'rsmspark_buttons_config_defaults', $defaults );
	}

	/**
	 * @return array<string, mixed>
	 */
	public static function base_defaults() {
		return array(
			'text_line_1'         => '',
			'text_line_2'         => '',
			'icon_type'           => 'sprite',
			'icon'                => '',
			'icon_image_id'       => 0,
			'icon_color'          => '',
			'icon_position'       => 'left',
			'shape'               => 'rounded',
			'border_radius'       => 8,
			'size'                => 'medium',
			'width'               => 'auto',
			'custom_width_px'     => 200,
			'padding_x'           => 0,
			'padding_y'           => 0,
			'font_size'           => 0,
			'font_weight'         => '600',
			'text_transform'      => 'none',
			'bg_type'             => 'solid',
			'bg_color'            => '#2563eb',
			'bg_hover_color'      => '#1d4ed8',
			'bg_gradient'         => '',
			'gradient_start'      => '#2563eb',
			'gradient_end'        => '#7c3aed',
			'gradient_angle'      => 135,
			'text_color'          => '#ffffff',
			'text_hover_color'    => '#ffffff',
			'border_color'        => 'transparent',
			'border_hover_color'  => 'transparent',
			'border_width'        => 0,
			'border_style'        => 'solid',
			'shadow'              => 'soft',
			'hover_effect'        => 'lift',
			'transition_duration' => 0.2,
			'link_type'           => 'url',
			'link_url'            => '',
			'link_post_id'        => 0,
			'link_post_type'      => '',
			'target_blank'        => false,
			'rel'                 => 'noopener noreferrer',
			'extra_class'         => '',
			'aria_label'          => '',
			'button_id'           => '',
		);
	}

	/**
	 * @param int $post_id Button post ID.
	 * @return array<string, mixed>
	 */
	public static function get( $post_id ) {
		$post_id = absint( $post_id );
		if ( $post_id <= 0 ) {
			return self::defaults();
		}

		$stored = get_post_meta( $post_id, self::META_KEY, true );
		if ( ! is_array( $stored ) ) {
			$stored = self::get_legacy_meta( $post_id );
		}

		if ( empty( $stored ) ) {
			$stored = array();
		}

		self::ensure_icons_loaded();

		return Rsmspark_Buttons_Icons::normalize_config( wp_parse_args( $stored, self::defaults() ) );
	}

	/**
	 * @param int                  $post_id Post ID.
	 * @param array<string, mixed> $config  Config.
	 * @return void
	 */
	public static function save( $post_id, array $config ) {
		update_post_meta( absint( $post_id ), self::META_KEY, self::sanitize( $config ) );
	}

	/**
	 * @param array<string, mixed> $input Raw input.
	 * @return array<string, mixed>
	 */
	public static function sanitize( array $input ) {
		$defaults = self::base_defaults();
		$out      = wp_parse_args( $input, $defaults );

		$out['text_line_1']    = sanitize_text_field( (string) $out['text_line_1'] );
		$out['text_line_2']    = sanitize_text_field( (string) $out['text_line_2'] );
		$out['icon_type']      = in_array( $out['icon_type'], array( 'sprite', 'dashicon', 'image' ), true ) ? $out['icon_type'] : 'sprite';
		$out['icon']           = self::sanitize_icon( $out['icon'] );
		$out['icon_image_id']  = absint( $out['icon_image_id'] );
		if ( 'image' === $out['icon_type'] && $out['icon_image_id'] > 0 && ! wp_attachment_is_image( $out['icon_image_id'] ) ) {
			$out['icon_image_id'] = 0;
			$out['icon_type']     = 'sprite';
		}

		if ( 'image' !== $out['icon_type'] ) {
			self::ensure_icons_loaded();
			$out = Rsmspark_Buttons_Icons::normalize_config( $out );
		}

		$out['icon_color']     = self::sanitize_color( $out['icon_color'], '', true );
		$out['icon_position'] = in_array( $out['icon_position'], array( 'left', 'right' ), true ) ? $out['icon_position'] : 'left';
		$out['shape']          = in_array( $out['shape'], array( 'rectangle', 'rounded', 'pill' ), true ) ? $out['shape'] : 'rounded';
		$out['border_radius']  = max( 0, min( 50, absint( $out['border_radius'] ) ) );
		$out['size']           = in_array( $out['size'], array( 'small', 'medium', 'large', 'custom' ), true ) ? $out['size'] : 'medium';
		$out['width']          = in_array( $out['width'], array( 'auto', 'full', 'custom_px' ), true ) ? $out['width'] : 'auto';
		$out['custom_width_px'] = max( 40, min( 1200, absint( $out['custom_width_px'] ) ) );
		$out['padding_x']      = max( 0, min( 80, absint( $out['padding_x'] ) ) );
		$out['padding_y']      = max( 0, min( 80, absint( $out['padding_y'] ) ) );
		$out['font_size']      = max( 0, min( 48, absint( $out['font_size'] ) ) );
		$out['font_weight']    = in_array( (string) $out['font_weight'], array( '400', '500', '600', '700' ), true ) ? (string) $out['font_weight'] : '600';
		$out['text_transform'] = in_array( $out['text_transform'], array( 'none', 'uppercase' ), true ) ? $out['text_transform'] : 'none';
		$out['bg_type']        = 'solid';

		$out['bg_color']           = self::sanitize_color( $out['bg_color'], $defaults['bg_color'], true );
		$out['bg_hover_color']     = self::sanitize_color( $out['bg_hover_color'], $defaults['bg_hover_color'], true );
		$out['gradient_start']     = self::sanitize_color( $out['gradient_start'], $defaults['gradient_start'] );
		$out['gradient_end']       = self::sanitize_color( $out['gradient_end'], $defaults['gradient_end'] );
		$out['gradient_angle']     = max( 0, min( 360, absint( $out['gradient_angle'] ) ) );

		$out['bg_gradient'] = '';
		$out['text_color']         = self::sanitize_color( $out['text_color'], $defaults['text_color'] );
		$out['text_hover_color']   = self::sanitize_color( $out['text_hover_color'], $defaults['text_hover_color'] );
		$out['border_color']       = self::sanitize_color( $out['border_color'], 'transparent', true );
		$out['border_hover_color'] = self::sanitize_color( $out['border_hover_color'], 'transparent', true );
		$out['border_width']       = max( 0, min( 8, absint( $out['border_width'] ) ) );
		$out['border_style']       = in_array( $out['border_style'], array( 'solid', 'dashed', 'dotted' ), true ) ? $out['border_style'] : 'solid';
		$out['shadow']             = in_array( $out['shadow'], array( 'none', 'soft', 'medium', 'strong' ), true ) ? $out['shadow'] : 'soft';
		$allowed_hovers = array( 'none', 'lift', 'scale', 'glow', 'lift-glow' );
		$out['hover_effect']       = in_array( $out['hover_effect'], $allowed_hovers, true ) ? $out['hover_effect'] : 'lift';
		$out['transition_duration'] = max( 0.1, min( 0.5, (float) $out['transition_duration'] ) );
		$link_type             = in_array( $out['link_type'], array( 'url', 'post' ), true ) ? $out['link_type'] : 'url';
		$out['link_post_id']   = absint( $out['link_post_id'] );
		$out['link_post_type'] = sanitize_key( (string) $out['link_post_type'] );

		if ( 'post' === $link_type && $out['link_post_id'] > 0 ) {
			$out['link_type']      = 'post';
			$out['link_post_type'] = $out['link_post_type'] ?: (string) get_post_type( $out['link_post_id'] );
		} else {
			$out['link_type']      = 'url';
			$out['link_post_id']   = 0;
			$out['link_post_type'] = '';
		}

		$out['link_url'] = self::sanitize_link_url( $out['link_url'] );
		$out['target_blank']       = ! empty( $out['target_blank'] );
		$out['rel']                = sanitize_text_field( (string) $out['rel'] );
		$out['extra_class']        = self::sanitize_extra_classes( $out['extra_class'] );
		$out['aria_label']         = sanitize_text_field( (string) $out['aria_label'] );
		$out['button_id']          = sanitize_html_class( (string) $out['button_id'] );

		if ( 'pill' === $out['shape'] ) {
			$out['border_radius'] = 50;
		}

		return $out;
	}

	/**
	 * @param array<string, mixed> $atts Shortcode attributes.
	 * @return array<string, mixed>
	 */
	public static function sanitize_atts( array $atts ) {
		$mapped = array();
		foreach ( $atts as $key => $value ) {
			$mapped[ str_replace( '-', '_', sanitize_key( (string) $key ) ) ] = $value;
		}

		if ( isset( $mapped['url'] ) && ! isset( $mapped['link_url'] ) ) {
			$mapped['link_url'] = $mapped['url'];
			$mapped['link_type'] = 'url';
		}

		if ( ! empty( $mapped['target_blank'] ) ) {
			$mapped['target_blank'] = filter_var( $mapped['target_blank'], FILTER_VALIDATE_BOOLEAN );
		}

		return self::sanitize( $mapped );
	}

	/**
	 * Sanitize only attribute keys present in the request (for saved-button embeds).
	 *
	 * @param array<string, mixed> $atts Shortcode or block attributes.
	 * @return array<string, mixed>
	 */
	public static function sanitize_atts_partial( array $atts ) {
		$allowed = array_keys( self::base_defaults() );
		$mapped  = array();

		foreach ( $atts as $key => $value ) {
			$key = str_replace( '-', '_', sanitize_key( (string) $key ) );
			if ( 'id' === $key || ! in_array( $key, $allowed, true ) ) {
				continue;
			}
			$mapped[ $key ] = $value;
		}

		if ( empty( $mapped ) ) {
			return array();
		}

		if ( isset( $mapped['url'] ) && ! isset( $mapped['link_url'] ) ) {
			$mapped['link_url']  = $mapped['url'];
			$mapped['link_type'] = 'url';
			unset( $mapped['url'] );
		}

		if ( array_key_exists( 'target_blank', $mapped ) ) {
			$mapped['target_blank'] = filter_var( $mapped['target_blank'], FILTER_VALIDATE_BOOLEAN );
		}

		$sanitized = self::sanitize( wp_parse_args( $mapped, self::base_defaults() ) );
		$partial   = array();

		foreach ( array_keys( $mapped ) as $key ) {
			if ( array_key_exists( $key, $sanitized ) ) {
				$partial[ $key ] = $sanitized[ $key ];
			}
		}

		return $partial;
	}

	/**
	 * @param int $post_id Post ID.
	 * @return array<string, mixed>
	 */
	private static function get_legacy_meta( $post_id ) {
		$post_id = absint( $post_id );
		if ( $post_id <= 0 ) {
			return array();
		}

		$legacy = array();
		$keys   = array_keys( self::defaults() );

		foreach ( $keys as $key ) {
			$value = get_post_meta( $post_id, '_rsm_btn_' . $key, true );
			if ( '' !== $value && false !== $value ) {
				$legacy[ $key ] = $value;
			}
		}

		$flat = get_post_meta( $post_id, 'rsmspark_button_config', true );
		if ( is_array( $flat ) && ! empty( $flat ) ) {
			$legacy = array_merge( $legacy, $flat );
		}

		return is_array( $legacy ) ? $legacy : array();
	}

	/**
	 * @param mixed $url Link URL, path, or same-page anchor.
	 * @return string
	 */
	public static function sanitize_link_url( $url ) {
		$url = trim( (string) $url );
		if ( '' === $url ) {
			return '';
		}

		if ( str_starts_with( $url, '#' ) ) {
			$fragment = substr( $url, 1 );
			$fragment = preg_replace( '/[^a-zA-Z0-9\-_.%~]/', '', (string) $fragment );
			return '#' . $fragment;
		}

		if ( preg_match( '/^(\/|\?)/', $url ) ) {
			return preg_replace( '/[<>"\']/', '', $url );
		}

		$sanitized = esc_url_raw( $url );
		if ( '' !== $sanitized ) {
			return $sanitized;
		}

		return preg_replace( '/[<>"\']/', '', $url );
	}

	/**
	 * @return void
	 */
	private static function ensure_icons_loaded() {
		if ( ! class_exists( 'Rsmspark_Buttons_Icons', false ) ) {
			require_once RSMSPARK_CONTENT_WIDGETS_PATH . 'includes/buttons/class-rsmspark-buttons-icons.php';
		}
	}

	/**
	 * @param mixed $icon Icon value.
	 * @return string
	 */
	public static function sanitize_icon( $icon ) {
		$icon = trim( (string) $icon );
		$icon = str_replace( array( 'dashicons ', 'dashicons-' ), '', $icon );
		$icon = sanitize_key( $icon );

		return $icon;
	}

	/**
	 * @param mixed $classes Extra classes.
	 * @return string
	 */
	private static function sanitize_extra_classes( $classes ) {
		$parts  = preg_split( '/\s+/', trim( (string) $classes ) ) ?: array();
		$clean  = array();

		foreach ( $parts as $part ) {
			$class = sanitize_html_class( (string) $part );
			if ( '' !== $class ) {
				$clean[] = $class;
			}
		}

		return implode( ' ', array_unique( $clean ) );
	}

	/**
	 * @param mixed  $color    Color value.
	 * @param string $fallback Fallback.
	 * @param bool   $allow_transparent Allow transparent keyword.
	 * @return string
	 */
	private static function sanitize_color( $color, $fallback, $allow_transparent = false ) {
		$color = trim( (string) $color );
		if ( $allow_transparent && in_array( strtolower( $color ), array( 'transparent', 'none' ), true ) ) {
			return 'transparent';
		}

		$sanitized = sanitize_hex_color( $color );
		return $sanitized ? $sanitized : $fallback;
	}
}
