<?php
/**
 * Sanitize play JSON payloads (import + programmatic saves).
 *
 * @package CartCue
 */

namespace CartCue;

defined( 'ABSPATH' ) || exit;

final class PlayPayloadSanitizer {

	/**
	 * Sanitize an imported play array before DB insert.
	 *
	 * @param array<string,mixed> $play   Raw play from JSON.
	 * @param Plugin              $plugin Plugin instance for slug validation.
	 * @return array<string,mixed>|\WP_Error
	 */
	public static function sanitize_imported_play( array $play, Plugin $plugin ) {
		$trigger_slug = sanitize_key( (string) ( $play['trigger_slug'] ?? '' ) );
		if ( '' === $trigger_slug || ! $plugin->get_trigger( $trigger_slug ) ) {
			return new \WP_Error( 'cartcue_import_trigger', __( 'Unknown or unavailable trigger in import file.', 'cartcue-sales-automation' ) );
		}
		if ( ! $plugin->is_pro() ) {
			$trigger = $plugin->get_trigger( $trigger_slug );
			if ( $trigger instanceof Triggers\GhostTrigger ) {
				return new \WP_Error( 'cartcue_import_trigger', __( 'Pro-only triggers cannot be imported on the free plan.', 'cartcue-sales-automation' ) );
			}
		}

		$trigger_settings = self::sanitize_trigger_settings( (array) ( $play['trigger_settings'] ?? [] ), $trigger_slug );
		$rules            = self::sanitize_rules( (array) ( $play['rules'] ?? [] ), $plugin );
		$actions          = self::sanitize_actions( (array) ( $play['actions'] ?? [] ), $plugin );
		$sequence         = self::sanitize_sequence( (array) ( $play['sequence'] ?? [] ), $plugin );
		$timing           = self::sanitize_timing( (array) ( $play['timing'] ?? [ 'type' => 'immediate' ] ) );

		if ( is_wp_error( $rules ) ) {
			return $rules;
		}
		if ( is_wp_error( $actions ) ) {
			return $actions;
		}

		$max_seq = $plugin->max_sequence_steps();
		if ( $max_seq > 0 && count( $sequence ) > $max_seq ) {
			$sequence = array_slice( $sequence, 0, $max_seq );
		}

		return [
			'name'                    => sanitize_text_field( (string) ( $play['name'] ?? 'Imported play' ) ),
			'trigger_slug'            => $trigger_slug,
			'trigger_settings'        => $trigger_settings,
			'rules'                   => $rules,
			'actions'                 => $actions,
			'sequence'                => $sequence,
			'timing'                  => $timing,
			'max_runs_per_customer'   => max( 0, (int) ( $play['max_runs_per_customer'] ?? 0 ) ),
			'cooldown_days'           => max( 0, (int) ( $play['cooldown_days'] ?? 0 ) ),
		];
	}

	/**
	 * @param array<string,mixed> $settings Raw trigger settings.
	 * @return array<string,string>
	 */
	public static function sanitize_trigger_settings( array $settings, string $trigger_slug ): array {
		$out = [];
		foreach ( $settings as $k => $v ) {
			if ( ! is_scalar( $v ) ) {
				continue;
			}
			$out[ sanitize_key( (string) $k ) ] = sanitize_text_field( (string) $v );
		}
		if ( 'inbound_webhook' === $trigger_slug && '' === (string) ( $out['token'] ?? '' ) ) {
			$out['token'] = wp_generate_password( 24, false, false );
		}
		return $out;
	}

	/**
	 * @param array<int,mixed> $rules Raw rules.
	 * @return array<int,array<string,string>>|\WP_Error
	 */
	public static function sanitize_rules( array $rules, Plugin $plugin ) {
		$out = [];
		foreach ( $rules as $r ) {
			if ( ! is_array( $r ) || empty( $r['slug'] ) ) {
				continue;
			}
			$slug = sanitize_key( (string) $r['slug'] );
			if ( ! $plugin->get_rule( $slug ) ) {
				return new \WP_Error( 'cartcue_import_rule', __( 'Import contains an unknown rule type.', 'cartcue-sales-automation' ) );
			}
			$out[] = [
				'slug'     => $slug,
				'operator' => sanitize_key( (string) ( $r['operator'] ?? 'equals' ) ),
				'value'    => sanitize_text_field( (string) ( $r['value'] ?? '' ) ),
			];
		}
		return $out;
	}

	/**
	 * @param array<int,mixed> $actions Raw actions.
	 * @return array<int,array<string,mixed>>|\WP_Error
	 */
	public static function sanitize_actions( array $actions, Plugin $plugin ) {
		$out = [];
		foreach ( $actions as $a ) {
			if ( ! is_array( $a ) || empty( $a['type'] ) ) {
				continue;
			}
			$type = sanitize_key( (string) $a['type'] );
			if ( ! $plugin->get_action( $type ) ) {
				return new \WP_Error( 'cartcue_import_action', __( 'Import contains an unknown action type.', 'cartcue-sales-automation' ) );
			}

			$s            = [];
			$settings_raw = (array) ( $a['settings'] ?? [] );
			$body_mode    = isset( $settings_raw['body_mode'] )
				? sanitize_key( (string) $settings_raw['body_mode'] )
				: '';

			foreach ( $settings_raw as $sk => $sv ) {
				if ( ! is_scalar( $sv ) && ! is_string( $sv ) ) {
					continue;
				}
				$ck = sanitize_key( (string) $sk );
				if ( 'body' === $ck ) {
					$s[ $ck ] = EmailBlockRenderer::sanitize_body_setting( (string) $sv, $body_mode );
				} elseif ( in_array( $ck, [ 'message', 'note_content', 'extra_payload' ], true ) ) {
					$s[ $ck ] = wp_kses_post( (string) $sv );
				} elseif ( 'bcc' === $ck ) {
					$s[ $ck ] = sanitize_text_field( (string) $sv );
				} elseif ( 'content_format' === $ck ) {
					$cf       = sanitize_key( (string) $sv );
					$s[ $ck ] = in_array( $cf, [ 'html', 'plain' ], true ) ? $cf : 'html';
				} else {
					$s[ $ck ] = sanitize_text_field( (string) $sv );
				}
			}

			$entry = [ 'type' => $type, 'settings' => $s ];
			if ( isset( $a['condition'] ) && is_array( $a['condition'] ) && ! empty( $a['condition']['enabled'] ) ) {
				$field = sanitize_key( (string) ( $a['condition']['field'] ?? '' ) );
				if ( '' !== $field ) {
					$entry['condition'] = [
						'enabled'  => true,
						'field'    => $field,
						'operator' => sanitize_key( (string) ( $a['condition']['operator'] ?? 'equals' ) ),
						'value'    => sanitize_text_field( (string) ( $a['condition']['value'] ?? '' ) ),
					];
				}
			}
			$out[] = $entry;
		}
		return $out;
	}

	/**
	 * @param array<int,mixed> $sequence Raw sequence steps.
	 * @return array<int,array<string,mixed>>
	 */
	public static function sanitize_sequence( array $sequence, Plugin $plugin ): array {
		$out = [];
		foreach ( $sequence as $step ) {
			if ( ! is_array( $step ) ) {
				continue;
			}

			$step_type = sanitize_key( (string) ( $step['step_type'] ?? 'action' ) );
			if ( 'branch' === $step_type && ! $plugin->can_use_branching() ) {
				continue;
			}
			$unit      = sanitize_key( (string) ( $step['delay_unit'] ?? 'hours' ) );
			$unit      = in_array( $unit, [ 'minutes', 'hours', 'days' ], true ) ? $unit : 'hours';
			$delay     = max( 0, (int) ( $step['delay'] ?? 1 ) );

			if ( 'branch' === $step_type ) {
				$rules = [];
				foreach ( (array) ( $step['rules'] ?? [] ) as $rule ) {
					if ( ! is_array( $rule ) || empty( $rule['slug'] ) ) {
						continue;
					}
					$rules[] = [
						'slug'     => sanitize_key( (string) $rule['slug'] ),
						'operator' => sanitize_key( (string) ( $rule['operator'] ?? 'is' ) ),
						'value'    => sanitize_text_field( (string) ( $rule['value'] ?? '' ) ),
					];
				}
				if ( empty( $rules ) ) {
					continue;
				}
				$entry = [
					'step_type'      => 'branch',
					'rules'          => $rules,
					'next_if_true'   => max( 0, (int) ( $step['next_if_true'] ?? 0 ) ),
					'next_if_false'  => max( 0, (int) ( $step['next_if_false'] ?? 0 ) ),
					'delay'          => $delay,
					'delay_unit'     => $unit,
				];
				if ( isset( $step['next_step'] ) ) {
					$entry['next_step'] = max( 0, (int) $step['next_step'] );
				}
				$out[] = $entry;
				continue;
			}

			if ( ! isset( $step['action_index'] ) || '' === $step['action_index'] ) {
				continue;
			}
			$entry = [
				'step_type'    => 'action',
				'action_index' => (int) $step['action_index'],
				'delay'        => $delay,
				'delay_unit'   => $unit,
			];
			if ( isset( $step['next_step'] ) ) {
				$entry['next_step'] = max( 0, (int) $step['next_step'] );
			}
			$out[] = $entry;
		}
		return $out;
	}

	/**
	 * @param array<string,mixed> $timing Raw timing config.
	 * @return array<string,mixed>
	 */
	public static function sanitize_timing( array $timing ): array {
		$type = sanitize_key( (string) ( $timing['type'] ?? 'immediate' ) );
		if ( 'delay' === $type ) {
			$unit = sanitize_key( (string) ( $timing['delay_unit'] ?? 'hours' ) );
			return [
				'type'         => 'delay',
				'delay_value'  => max( 1, (int) ( $timing['delay_value'] ?? 1 ) ),
				'delay_unit'   => in_array( $unit, [ 'minutes', 'hours', 'days' ], true ) ? $unit : 'hours',
			];
		}
		if ( 'schedule_time' === $type ) {
			return [
				'type'             => 'schedule_time',
				'schedule_hour'    => min( 23, max( 0, (int) ( $timing['schedule_hour'] ?? 9 ) ) ),
				'schedule_minute'  => min( 59, max( 0, (int) ( $timing['schedule_minute'] ?? 0 ) ) ),
			];
		}
		return [ 'type' => 'immediate' ];
	}
}
