<?php

namespace Limb_Chatbot\Includes\Services\Actions\Executors;

use Limb_Chatbot\Includes\Data_Objects\Action_Callback;
use Limb_Chatbot\Includes\Exceptions\Error_Codes;
use Limb_Chatbot\Includes\Exceptions\Exception as Custom_Exception;
use Limb_Chatbot\Includes\Services\Actions\Action_Callback_Execution_Context;
use Limb_Chatbot\Includes\Services\Actions\Slack_Message_Builder;


/**
 * Slack Callback Executor
 *
 * Executes Slack callbacks by sending beautifully formatted messages to Slack via webhook.
 * Automatically includes user information and submitted parameters in messages.
 *
 * @package Limb_Chatbot\Includes\Services\Actions\Executors
 * @since 1.0.0
 */
class Slack_Callback_Executor extends Abstract_Callback_Executor {

	/**
	 * Get callback type.
	 *
	 * @return string
	 * @since 1.0.0
	 */
	public function get_type(): string {
		return Action_Callback::TYPE_SLACK;
	}

	/**
	 * Get required configuration fields.
	 *
	 * @return array Required field names.
	 * @since 1.0.0
	 */
	public function get_required_fields(): array {
		return [ 'content', 'webhook_url' ];
	}

	/**
	 * Validate configuration.
	 *
	 * Ensures webhook URL and content are provided.
	 *
	 * @param  array  $config  Configuration to validate.
	 *
	 * @return bool True if valid.
	 * @throws Custom_Exception
	 * @since 1.0.0
	 */
	public function validate_config( array $config ): bool {
		// Check required fields
		parent::validate_config( $config );

		$webhook_url = esc_url_raw( $config['webhook_url'] ?? '' );
		if ( empty( $webhook_url ) || ! filter_var( $webhook_url, FILTER_VALIDATE_URL ) ) {
			throw new Custom_Exception(
				Error_Codes::VALIDATION_INVALID_VALUE,
				__( 'Please provide a valid Slack webhook URL.', 'limb-chatbot' )
			);
		}

		return true;
	}

	/**
	 * Execute Slack callback.
	 *
	 * Sends a beautifully formatted message to Slack using incoming webhook.
	 * Includes user information and submitted parameters automatically.
	 *
	 * @param  array  $config  Configuration.
	 * @param  Action_Callback_Execution_Context  $context  Execution context.
	 *
	 * @return Callback_Executor_Response Response object with data and metadata.
	 * @throws Custom_Exception On execution failure.
	 * @since 1.0.0
	 */
	public function execute_callback( array $config, Action_Callback_Execution_Context $context ): Callback_Executor_Response {
		$webhook_url = esc_url_raw( $config['webhook_url'] ?? '' );

		// Build message payload with blocks
		$slack_message_builder = new Slack_Message_Builder();
		$title                 = ! empty( $config['title'] ) ? $config['title'] : __( '🤖 New Action Submission', 'limb-chatbot' );
		$payload               = $slack_message_builder->build( $config['content'], $context, $title );
		// Send message to Slack
		$this->send_slack_message( $webhook_url, $payload );

		// Return success response
		return Callback_Executor_Response::success(
			[
				'sent'          => true,
				'message'       => $config['content'],
				'sent_at'       => current_time( 'mysql', true ),
			],
			[
				'webhook_url' => $webhook_url,
			]
		);
	}

	/**
	 * Send message to Slack using incoming webhook URL.
	 *
	 * @param  string  $webhook_url  Incoming webhook URL.
	 * @param  array  $payload  Message payload.
	 *
	 * @return array Slack API response.
	 * @throws Custom_Exception If sending fails.
	 * @since 1.0.0
	 */
	private function send_slack_message( string $webhook_url, array $payload ): array {
		$response = wp_remote_post(
			$webhook_url,
			[
				'headers' => [
					'Content-Type' => 'application/json',
				],
				'body'    => wp_json_encode( $payload ),
				'timeout' => 30,
			]
		);
		if ( is_wp_error( $response ) ) {
			throw new Custom_Exception(
				Error_Codes::TECHNICAL_ERROR,
				sprintf(
				/* translators: %s: error message */
					__( 'Failed to send Slack message: %s', 'limb-chatbot' ),
					$response->get_error_message()
				),
				null,
				500
			);
		}

		$code = (int) wp_remote_retrieve_response_code( $response );
		$body = wp_remote_retrieve_body( $response );

		if ( $code < 200 || $code >= 300 ) {
			throw new Custom_Exception(
				Error_Codes::TECHNICAL_ERROR,
				sprintf(
				/* translators: %s: Slack response body */
					__( 'Slack webhook error: %s', 'limb-chatbot' ),
					$body ?: __( 'Unknown error', 'limb-chatbot' )
				),
				[ 'status' => $code, 'body' => $body ],
				$code
			);
		}

		return [
			'ok'   => true,
			'body' => $body,
		];
	}
}
