<?php

namespace Limb_Chatbot\Includes\Api\V1\Controllers\Integrations;

use Limb_Chatbot\Includes\Api\V1\Controllers\Rest_Controller;
use Limb_Chatbot\Includes\Data_Objects\Config;
use Limb_Chatbot\Includes\Data_Objects\Setting;
use Limb_Chatbot\Includes\Integrations\Telegram\Services\Telegram_Agent_Service;
use Limb_Chatbot\Includes\Integrations\Telegram\Services\Telegram_Event_Handler_Service;
use Limb_Chatbot\Includes\Integrations\Telegram\Telegram;
use Limb_Chatbot\Includes\Integrations\Telegram\Utilities\Users_Utility;
use Limb_Chatbot\Includes\Services\Collection;
use Limb_Chatbot\Includes\Services\Helper;
use WP_Error;
use WP_REST_Request;
use WP_REST_Response;
use WP_REST_Server;

/**
 * Telegram Controller
 *
 * REST API controller for Telegram integration endpoints.
 * Provides endpoints for:
 * - Fetching private chat users
 * - Receiving Telegram webhook updates
 *
 * @package Limb_Chatbot\Includes\Api\V1\Controllers\Integrations
 * @since 1.0.11
 */
class Telegram_Controller extends Rest_Controller {

	/**
	 * REST route base.
	 *
	 * @var string
	 * @since 1.0.11
	 */
	protected $rest_base = 'integrations/telegram';

	/**
	 * Registers REST routes for Telegram integration.
	 *
	 * @return void
	 * @since 1.0.11
	 */
	public function register_routes() {
		// GET /integrations/telegram/users?config_id=24
		register_rest_route(
			$this->namespace,
			'/' . $this->rest_base . '/users',
			array(
				array(
					'methods'             => WP_REST_Server::READABLE,
					'callback'            => array( $this, 'get_users' ),
					'permission_callback' => array( $this, 'permission_callback' ),
					'args'                => $this->get_users_args(),
				),
				'schema' => array( $this, 'get_users_schema' ),
			)
		);

		// GET /integrations/telegram/agents?config_id=24
		register_rest_route(
			$this->namespace,
			'/' . $this->rest_base . '/agents',
			array(
				array(
					'methods'             => WP_REST_Server::READABLE,
					'callback'            => array( $this, 'get_agents' ),
					'permission_callback' => array( $this, 'permission_callback' ),
					'args'                => $this->get_config_id_arg(),
				),
			)
		);

		// POST /integrations/telegram/agents?config_id=24
		register_rest_route(
			$this->namespace,
			'/' . $this->rest_base . '/agents',
			array(
				array(
					'methods'             => WP_REST_Server::CREATABLE,
					'callback'            => array( $this, 'create_agents' ),
					'permission_callback' => array( $this, 'permission_callback' ),
					'args'                => $this->get_telegram_agent_ids_arg(),
				),
			)
		);

		// POST /integrations/telegram/webhook (Public webhook for Telegram updates)
		register_rest_route(
			$this->namespace,
			'/' . $this->rest_base . '/webhook',
			array(
				array(
					'methods'             => WP_REST_Server::CREATABLE,
					'callback'            => array( $this, 'handle_webhook' ),
					'permission_callback' => '__return_true', // Public endpoint, validated via secret token
				),
			)
		);
	}

	/**
	 * Gets argument definitions for users endpoint.
	 *
	 * @return array Argument definitions.
	 * @since 1.0.11
	 */
	private function get_users_args(): array {
		return array_merge(
			$this->get_config_id_arg(),
			array(
				'refresh' => array(
					'description' => __( 'Force refresh users from Telegram API', 'limb-chatbot' ),
					'type'        => 'boolean',
					'required'    => false,
					'default'     => false,
				),
			)
		);
	}

	/**
	 * Gets argument definition for config_id parameter.
	 *
	 * @return array Argument definition.
	 * @since 1.0.11
	 */
	private function get_config_id_arg(): array {
		return array(
			'config_id' => array(
				'description'       => __( 'Telegram configuration ID', 'limb-chatbot' ),
				'type'              => 'integer',
				'required'          => true,
				'sanitize_callback' => 'absint',
				'validate_callback' => function ( $value ) {
					$config = Config::find( $value );
					if ( ! $config instanceof Config || ! $config->get_related_to_instance() instanceof Telegram ) {
						return false;
					}

					return true;
				},
			),
		);
	}

	/**
	 * Gets private chat users from Telegram bot updates.
	 *
	 * Fetches users from Telegram API and saves them to the config params.
	 * On subsequent requests (without refresh), returns saved users.
	 * When using event_subscription (webhook) mode, only returns saved users
	 * since Telegram disables getUpdates API when a webhook is set.
	 *
	 * @param  WP_REST_Request  $request  REST request object.
	 *
	 * @return WP_REST_Response|WP_Error Response with users list.
	 * @since 1.0.11
	 */
	public function get_users( $request ) {
		try {
			$config  = Config::find( $request->get_param( 'config_id' ) );
			$refresh = $request->get_param( 'refresh' );

			// Fetch users from Telegram API
			$utility = new Users_Utility( $config );
			$users   = $utility->list();

			// Merge with existing saved users (avoid duplicates)
			$saved_users = $params['users'] ?? [];
			$merged_users = $this->merge_users( $saved_users, $users );

			// Save users to config params
			$params['users'] = $merged_users;
			$config->params  = $params;
			$config->encrypt_params();
			$config->save();

			return rest_ensure_response( new Collection( $merged_users ) );
		} catch ( \Exception $e ) {
			Helper::log( $e, __METHOD__ );

			return Helper::get_wp_error( $e );
		}
	}

	/**
	 * Merge users arrays, avoiding duplicates by ID.
	 *
	 * @param array $existing Existing saved users.
	 * @param array $new      New users from API.
	 *
	 * @return array Merged users.
	 * @since 1.0.11
	 */
	private function merge_users( array $existing, array $new ): array {
		$merged = [];
		$seen_ids = [];

		// Add existing users first
		foreach ( $existing as $user ) {
			$id = $user['id'] ?? null;
			if ( $id && ! isset( $seen_ids[ $id ] ) ) {
				$seen_ids[ $id ] = true;
				$merged[] = $user;
			}
		}

		// Add new users
		foreach ( $new as $user ) {
			$id = $user['id'] ?? null;
			if ( $id && ! isset( $seen_ids[ $id ] ) ) {
				$seen_ids[ $id ] = true;
				$merged[] = $user;
			}
		}

		return $merged;
	}

	/**
	 * Gets agents (users) from Telegram bot to be added as live agents.
	 *
	 * Returns list of Telegram users that can be imported as live agents.
	 * This is similar to get_users but specifically for the agent creation flow.
	 *
	 * @param  WP_REST_Request  $request  REST request object.
	 *
	 * @return WP_REST_Response|WP_Error Response with agents list.
	 * @since 1.0.11
	 */
	public function get_agents( $request ) {
		try {
			$config = Config::find( $request->get_param( 'config_id' ) );

			// Fetch users from Telegram API using Users_Utility
			$utility = new Users_Utility( $config );
			$users   = $utility->list_with_profile_photos();

			return rest_ensure_response( new Collection( $users ) );
		} catch ( \Exception $e ) {
			Helper::log( $e, __METHOD__ );

			return Helper::get_wp_error( $e );
		}
	}

	/**
	 * Creates agents (WordPress and Chatbot users) from Telegram user IDs.
	 *
	 * @param  WP_REST_Request  $request  REST request object.
	 *
	 * @return WP_REST_Response|WP_Error Response with creation results.
	 * @since 1.0.11
	 */
	public function create_agents( $request ) {
		try {
			$config   = Config::find( $request->get_param( 'config_id' ) );
			$user_ids = $request->get_param( 'ids' );
			// Create agents
			$service = new Telegram_Agent_Service();
			$results = $service->create_agents_from_telegram_users( $user_ids, $config );

			return rest_ensure_response( $results );
		} catch ( \Exception $e ) {
			Helper::log( $e, __METHOD__ );

			return Helper::get_wp_error( $e );
		}
	}

	/**
	 * Handle Telegram webhook.
	 *
	 * Public endpoint for receiving Telegram updates via webhook.
	 * Validates the secret token header before processing.
	 *
	 * @param WP_REST_Request $request Request object.
	 *
	 * @return WP_REST_Response Response object.
	 * @since 1.0.11
	 */
	public function handle_webhook( $request ): WP_REST_Response {
		try {
			$body = $request->get_json_params();

			// Verify secret token for security
			$config = $this->verify_secret_token( $request );
			if ( ! $config ) {
				return rest_ensure_response( [
					'success' => false,
					'message' => __( 'Invalid secret token', 'limb-chatbot' )
				] );
			}

			// Handle the update
			$handler = new Telegram_Event_Handler_Service();
			$handler->handle_update( $body, $config );

			return rest_ensure_response( [
				'success' => true,
				'message' => __( 'Update processed successfully', 'limb-chatbot' )
			] );

		} catch ( \Exception $e ) {
			Helper::log( $e, __METHOD__ );

			return rest_ensure_response( [
				'success' => false,
				'message' => __( 'Internal server error', 'limb-chatbot' )
			] );
		}
	}

	/**
	 * Verify Telegram secret token from header.
	 *
	 * Validates the X-Telegram-Bot-Api-Secret-Token header against
	 * stored secret tokens in Telegram configs.
	 *
	 * @param WP_REST_Request $request Request object.
	 *
	 * @return Config|null Config if valid, null otherwise.
	 * @since 1.0.11
	 */
	private function verify_secret_token( WP_REST_Request $request ): ?Config {

		$secret_token = $request->get_header( 'X-Telegram-Bot-Api-Secret-Token' );

		if ( empty( $secret_token ) ) {
			return null;
		}

		// Find config with matching secret token
		$configs = Config::where( [ 'related_to' => Telegram::class ] );
		if ( $configs->is_empty() ) {
			return null;
		}

		foreach ( $configs->get() as $config ) {
			if ( ! $config instanceof Config ) {
				continue;
			}

			$params = $config->get_params();
			if ( ! empty( $params['webhook_secret'] ) && hash_equals( $params['webhook_secret'], $secret_token ))
			{
				return $config;
			}
		}

		return null;
	}

	/**
	 * Gets the JSON schema for users response.
	 *
	 * @return array JSON schema.
	 * @since 1.0.11
	 */
	public function get_users_schema(): array {
		return array(
			'$schema'    => 'http://json-schema.org/draft-04/schema#',
			'title'      => 'telegram_users',
			'type'       => 'object',
			'properties' => array(
				'success' => array(
					'description' => __( 'Whether the request was successful', 'limb-chatbot' ),
					'type'        => 'boolean',
					'context'     => array( 'view' ),
					'readonly'    => true,
				),
				'items'   => array(
					'description' => __( 'Array of Telegram private chat users', 'limb-chatbot' ),
					'type'        => 'array',
					'context'     => array( 'view' ),
					'readonly'    => true,
					'items'       => array(
						'type'       => 'object',
						'properties' => array(
							'id'            => array( 'type' => 'integer' ),
							'chat_id'       => array( 'type' => 'integer' ),
							'first_name'    => array( 'type' => 'string' ),
							'last_name'     => array( 'type' => 'string' ),
							'username'      => array( 'type' => 'string' ),
							'language_code' => array( 'type' => 'string' ),
							'type'          => array( 'type' => 'string' ),
						),
					),
				),
				'total'   => array(
					'description' => __( 'Total number of users', 'limb-chatbot' ),
					'type'        => 'integer',
					'context'     => array( 'view' ),
					'readonly'    => true,
				),
			),
		);
	}

	/**
	 * Checks permission for Telegram endpoints.
	 *
	 * Requires user to be logged in and have manage_options capability.
	 *
	 * @param  WP_REST_Request  $request  REST request object.
	 *
	 * @return bool True if authorized, false otherwise.
	 * @since 1.0.11
	 */
	public function permission_callback( $request ): bool {
		if ( ! parent::permission_callback( $request ) ) {
			return false;
		}

		return current_user_can( 'manage_options' );
	}

	/**
	 * Gets argument definition for Telegram agent IDs.
	 *
	 * @return array Argument definition.
	 * @since 1.0.11
	 */
	private function get_telegram_agent_ids_arg(): array {
		return array_merge(
			$this->get_config_id_arg(),
			array(
				'ids' => array(
					'description'       => __( 'Array of Telegram user IDs', 'limb-chatbot' ),
					'type'              => 'array',
					'required'          => true,
					'validate_callback' => function ( $value ) {
						return is_array( $value ) && ! empty( $value );
					},
				),
			)
		);
	}
}

