<?php

namespace Limb_Chatbot\Includes\Integrations\Telegram\Services;

use Limb_Chatbot\Includes\Data_Objects\Config;
use Limb_Chatbot\Includes\Exceptions\Error_Codes;
use Limb_Chatbot\Includes\Exceptions\Exception;

/**
 * Service for validating Telegram integration configurations.
 *
 * Validates bot tokens using the Telegram getMe API endpoint.
 *
 * @package Limb_Chatbot\Includes\Integrations\Telegram\Services
 * @since 1.0.11
 */
class Telegram_Validation_Service {

	/**
	 * Telegram API base URL.
	 *
	 * @var string
	 * @since 1.0.11
	 */
	const API_BASE_URL = 'https://api.telegram.org';

	/**
	 * Validates the Telegram configuration.
	 *
	 * @param Config $config Configuration object containing Telegram credentials.
	 *
	 * @return true Validation result with status and details.
	 * @throws Exception If validation fails.
	 * @since 1.0.11
	 */
	public function validate( Config $config ) {
		$params = $config->get_params();

		// Validate required parameters
		$this->validate_required_params( $params );

		$bot_token = $params['bot_token'] ?? '';

		$validation_results = [
			'valid'     => true,
			'bot_token' => [ 'valid' => false, 'message' => '' ],
			'bot_info'  => null,
			'webhook'   => [ 'valid' => false, 'message' => '' ],
		];

		// Test bot token using getMe API call
		try {
			$bot_info = $this->test_bot_token( $bot_token );

			if ( isset( $bot_info['ok'] ) && $bot_info['ok'] === true && isset( $bot_info['result'] ) ) {
				$validation_results['bot_token']['valid']   = true;
				$validation_results['bot_token']['message'] = sprintf(
					/* translators: %s: bot username */
					__( 'Bot token is valid. Bot: @%s', 'limb-chatbot' ),
					$bot_info['result']['username'] ?? 'unknown'
				);
				$validation_results['bot_info'] = $bot_info['result'];
			} else {
				$error_message                              = $bot_info['description'] ?? __( 'Invalid bot token', 'limb-chatbot' );
				$validation_results['bot_token']['valid']   = false;
				$validation_results['bot_token']['message'] = $error_message;
				$validation_results['valid']                = false;
			}
		} catch ( \Exception $e ) {
			$validation_results['bot_token']['valid']   = false;
			$validation_results['bot_token']['message'] = $e->getMessage();
			$validation_results['valid']                = false;
		}

		// Check webhook configuration
		$webhook_url                    = $this->get_webhook_url();
		$validation_results['webhook']  = [
			'valid'   => true,
			'url'     => $webhook_url,
			'message' => sprintf(
				/* translators: %s: webhook URL */
				__( 'Configure this webhook URL for your Telegram bot: %s', 'limb-chatbot' ),
				$webhook_url
			),
		];

		if ( ! ( $validation_results['valid'] ?? false ) ) {
			$error_message = $this->build_validation_error_message( $validation_results );

			throw new Exception(
				Error_Codes::VALIDATION_INVALID_VALUE,
				$error_message,
				$validation_results,
				400
			);
		}

		return true;
	}

	/**
	 * Validates required parameters are present.
	 *
	 * @param array $params Configuration parameters.
	 *
	 * @throws Exception If required parameters are missing.
	 * @since 1.0.11
	 */
	private function validate_required_params( array $params ): void {
		$required = [ 'bot_token' ];
		$missing  = [];

		foreach ( $required as $param ) {
			if ( empty( $params[ $param ] ) ) {
				$missing[] = $param;
			}
		}

		if ( ! empty( $missing ) ) {
			throw new Exception(
				Error_Codes::VALIDATION_REQUIRED,
				sprintf(
					/* translators: %s: comma-separated list of missing parameters */
					__( 'Missing required parameters: %s', 'limb-chatbot' ),
					implode( ', ', $missing )
				),
				[ 'missing_params' => $missing ],
				400
			);
		}
	}

	/**
	 * Tests Telegram bot token using the getMe API endpoint.
	 *
	 * @param string $bot_token Telegram bot token.
	 *
	 * @return array Telegram API response.
	 * @throws Exception If API request fails.
	 * @since 1.0.11
	 */
	private function test_bot_token( string $bot_token ): array {
		// Validate token format (basic check)
		if ( ! $this->is_valid_token_format( $bot_token ) ) {
			throw new Exception(
				Error_Codes::VALIDATION_INVALID_VALUE,
				__( 'Invalid bot token format. Token should be in format: 123456789:ABCdefGhIJKlmNoPQRsTUVwxyZ', 'limb-chatbot' ),
				null,
				400
			);
		}

		$url = self::API_BASE_URL . '/bot' . $bot_token . '/getMe';

		$response = wp_remote_get(
			$url,
			[
				'timeout' => 15,
				'headers' => [
					'Content-Type' => 'application/json',
				],
			]
		);

		if ( is_wp_error( $response ) ) {
			throw new Exception(
				Error_Codes::TECHNICAL_ERROR,
				sprintf(
					/* translators: %s: error message */
					__( 'Failed to connect to Telegram API: %s', 'limb-chatbot' ),
					$response->get_error_message()
				),
				null,
				500
			);
		}

		$http_code = wp_remote_retrieve_response_code( $response );
		$body      = wp_remote_retrieve_body( $response );
		$data      = json_decode( $body, true );

		if ( json_last_error() !== JSON_ERROR_NONE ) {
			throw new Exception(
				Error_Codes::UNEXPECTED_RESPONSE_FORMAT,
				__( 'Invalid response from Telegram API', 'limb-chatbot' ),
				null,
				500
			);
		}

		// Handle specific HTTP error codes
		if ( $http_code === 401 || $http_code === 403 ) {
			return [
				'ok'          => false,
				'description' => __( 'Unauthorized: Invalid bot token', 'limb-chatbot' ),
				'error_code'  => $http_code,
			];
		}

		if ( $http_code === 404 ) {
			return [
				'ok'          => false,
				'description' => __( 'Bot not found: Token may be invalid or bot was deleted', 'limb-chatbot' ),
				'error_code'  => $http_code,
			];
		}

		return $data;
	}

	/**
	 * Validates the basic format of a Telegram bot token.
	 *
	 * Telegram bot tokens have the format: <bot_id>:<alphanumeric_string>
	 * Example: 123456789:ABCdefGhIJKlmNoPQRsTUVwxyZ
	 *
	 * @param string $token Bot token to validate.
	 *
	 * @return bool True if token format is valid.
	 * @since 1.0.11
	 */
	private function is_valid_token_format( string $token ): bool {
		// Token must contain a colon
		if ( strpos( $token, ':' ) === false ) {
			return false;
		}

		// Split token into bot_id and secret
		$parts = explode( ':', $token, 2 );

		if ( count( $parts ) !== 2 ) {
			return false;
		}

		[ $bot_id, $secret ] = $parts;

		// Bot ID must be numeric
		if ( ! ctype_digit( $bot_id ) ) {
			return false;
		}

		// Secret must be at least 20 characters (alphanumeric with underscores and dashes)
		if ( strlen( $secret ) < 20 ) {
			return false;
		}

		// Secret should only contain alphanumeric characters, underscores, and dashes
		if ( ! preg_match( '/^[A-Za-z0-9_-]+$/', $secret ) ) {
			return false;
		}

		return true;
	}

	/**
	 * Gets the webhook URL for Telegram integration.
	 *
	 * @return string Webhook URL.
	 * @since 1.0.11
	 */
	private function get_webhook_url(): string {
		return rest_url( 'limb/chatbot/v1/integrations/telegram/events' );
	}

	/**
	 * Builds a detailed error message from validation results.
	 *
	 * @param array $validation_result Validation result array.
	 *
	 * @return string Formatted error message.
	 * @since 1.0.11
	 */
	private function build_validation_error_message( array $validation_result ): string {
		$errors = [];

		// Bot token errors
		if ( isset( $validation_result['bot_token'] ) && ! $validation_result['bot_token']['valid'] ) {
			$errors[] = sprintf(
				__( 'Bot Token: %s', 'limb-chatbot' ),
				$validation_result['bot_token']['message']
			);
		}

		// Build final message
		if ( empty( $errors ) ) {
			return __( 'Telegram configuration is invalid. Please check your bot token.', 'limb-chatbot' );
		}

		return __( 'Telegram configuration validation failed: ', 'limb-chatbot' ) . implode( ' | ', $errors );
	}
}

