<?php

namespace Limb_Chatbot\Includes\Integrations\Telegram\Services;

use Limb_Chatbot\Includes\Data_Objects\Chatbot_User;
use Limb_Chatbot\Includes\Data_Objects\Config;
use Limb_Chatbot\Includes\Exceptions\Error_Codes;
use Limb_Chatbot\Includes\Exceptions\Exception;
use Limb_Chatbot\Includes\Integrations\Telegram\Utilities\Messages_Utility;
use Limb_Chatbot\Includes\Integrations\Telegram\Utilities\Users_Utility;
use Limb_Chatbot\Includes\Repositories\Chatbot_User_Repository;
use Limb_Chatbot\Includes\Services\Collection;

/**
 * Telegram Agent Service
 *
 * Handles creation of WordPress users and Chatbot users from Telegram user data.
 *
 * @package Limb_Chatbot\Includes\Integrations\Telegram\Services
 * @since 1.0.11
 */
class Telegram_Agent_Service {

	/**
	 * Creates WordPress users and Chatbot users from Telegram user data.
	 *
	 * @param  array  $user_ids  Array of Telegram user IDs (chat_id or id).
	 * @param  Config  $config  Telegram configuration.
	 *
	 * @return Collection Collection of created users with status.
	 * @throws Exception
	 * @since 1.0.11
	 */
	public function create_agents_from_telegram_users( array $user_ids, Config $config ): Collection {
		// Remove duplicate IDs to prevent processing the same user twice
		$user_ids = array_unique( $user_ids );

		// Fetch saved users from config params
		$params          = $config->get_params();
		$saved_users     = $params['users'] ?? [];
		$telegram_users  = [];

		// Map user_ids to actual Telegram users
		foreach ( $user_ids as $user_id ) {
			$found = false;
			foreach ( $saved_users as $saved_user ) {
				$saved_chat_id = (string) ( $saved_user['chat_id'] ?? $saved_user['id'] ?? '' );
				if ( $saved_chat_id === (string) $user_id ) {
					$telegram_users[] = $saved_user;
					$found = true;
					break;
				}
			}
			if ( ! $found ) {
				// Try to fetch from Telegram API
				try {
					$utility = new Users_Utility( $config );
					$utility->set_chat_id( $user_id );

					$user_data = $utility->retrieve();

					if ( ! empty( $user_data['id'] ) ) {
						$telegram_users[] = $user_data;
						$found            = true;
					}
				} catch ( \Exception $e ) {
					// Silent failure if fetch fails, will fallback to ID only
				}
			}

			if ( ! $found ) {
				$telegram_users[] = [
					'id' => $user_id
				];
			}
		}

		if ( empty( $telegram_users ) ) {
			throw new Exception(
				Error_Codes::NOT_FOUND,
				__( 'No valid Telegram users found with provided IDs.', 'limb-chatbot' ),
				null,
				400
			);
		}

		$this->ensure_agent_role_exists();
		$results = new Collection();

		foreach ( $telegram_users as $telegram_user ) {
			try {
				$result = $this->create_single_agent( $telegram_user, $config );
				$results->push_item( $result->with( [ 'agent' ] ) );
			} catch ( \Exception $e ) {
				$results->push_item( [
					'telegram_id' => $telegram_user['id'] ?? '',
					'success'     => false,
					'error'       => $e->getMessage(),
				] );
			}
		}

		return $results;
	}

	/**
	 * Creates a single agent from Telegram user data.
	 *
	 * @param array  $telegram_user Telegram user object.
	 * @param Config $config        Telegram configuration.
	 *
	 * @return Chatbot_User Result with created user.
	 * @throws Exception
	 * @since 1.0.11
	 */
	private function create_single_agent( array $telegram_user, Config $config ): Chatbot_User {
		$telegram_id = (string) ( $telegram_user['id'] ?? '' );

		if ( empty( $telegram_id ) ) {
			throw new Exception(
				Error_Codes::VALIDATION_INVALID_VALUE,
				__( 'Telegram user ID is required.', 'limb-chatbot' ),
				null,
				400
			);
		}

		// First, check if a chatbot user already exists for this Telegram ID
		$existing_chatbot_user = $this->get_chatbot_user_by_telegram_id( $telegram_id, $config );
		if ( $existing_chatbot_user instanceof Chatbot_User ) {
			return $existing_chatbot_user;
		}

		// Create new agent
		return $this->create_agent( $telegram_user, $config );
	}

	/**
	 * Get or create a chatbot user from Telegram user data.
	 *
	 * Creates the agent on-the-fly when a message is received from Telegram.
	 *
	 * @param array  $telegram_user Telegram user data from message.
	 * @param Config $config        Telegram configuration.
	 *
	 * @return Chatbot_User|null Chatbot user or null on failure.
	 * @since 1.0.11
	 */
	public function get_or_create_agent_from_telegram_user( array $telegram_user, Config $config ): ?Chatbot_User {
		$telegram_id = $telegram_user['id'] ?? '';

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

		// Check if a chatbot user already exists for this Telegram ID
		$existing_chatbot_user = $this->get_chatbot_user_by_telegram_id( (string) $telegram_id, $config );
		if ( $existing_chatbot_user instanceof Chatbot_User ) {
			// Update user info if changed
			$this->update_agent_info( $existing_chatbot_user, $telegram_user, $config );

			return $existing_chatbot_user;
		}

		// Create new chatbot user for this Telegram agent
		try {
			$new_agent = $this->create_agent( $telegram_user, $config );
			return $new_agent;
		} catch ( \Exception $e ) {
			return null;
		}
	}

	/**
	 * Creates a single agent from Telegram user data.
	 *
	 * @param array  $telegram_user Telegram user object.
	 * @param Config $config        Telegram configuration.
	 *
	 * @return Chatbot_User Result with created user.
	 * @throws Exception
	 * @since 1.0.11
	 */
	private function create_agent( array $telegram_user, Config $config ): Chatbot_User {
		$telegram_id = (string) ( $telegram_user['id'] ?? '' );
		$first_name  = $telegram_user['first_name'] ?? '';
		$last_name   = $telegram_user['last_name'] ?? '';
		$username    = $telegram_user['username'] ?? '';

		if ( empty( $telegram_id ) ) {
			throw new Exception(
				Error_Codes::VALIDATION_INVALID_VALUE,
				__( 'Telegram user ID is required.', 'limb-chatbot' ),
				null,
				400
			);
		}

		$this->ensure_agent_role_exists();

		// Determine base username by priority: 1. Username, 2. Name, 3. ID
		$base_username = $username;

		if ( empty( $base_username ) ) {
			$full_name = trim( $first_name . ' ' . $last_name );
			if ( ! empty( $full_name ) ) {
				// Replace spaces with underscores for better username format
				$base_username = str_replace( ' ', '_', $full_name );
			}
		}

		if ( empty( $base_username ) ) {
			$base_username = 'telegram_' . $telegram_id;
		}

		// Generate a unique username
		$wp_username = $this->generate_unique_username( $base_username );

		// Create WordPress user
		$display_name = trim( $first_name . ' ' . $last_name ) ?: $username ?: 'Telegram Agent';

		$user_data = [
			'user_login'   => $wp_username,
			'user_email'   => $wp_username . '@telegram.tg',
			'display_name' => $display_name,
			'first_name'   => $first_name,
			'last_name'    => $last_name,
			'role'         => Chatbot_User::ROLE_AGENT,
			'user_pass'    => wp_generate_password( 24, true, true ),
		];

		$wp_user_id = wp_insert_user( $user_data );

		if ( is_wp_error( $wp_user_id ) ) {
			// User might already exist, try to get by username
			$existing_user = get_user_by( 'login', $wp_username );
			if ( $existing_user ) {
				$wp_user_id = $existing_user->ID;
				// Ensure agent role
				if ( ! in_array( Chatbot_User::ROLE_AGENT, $existing_user->roles, true ) ) {
					$existing_user->add_role( Chatbot_User::ROLE_AGENT );
				}
			} else {
				throw new Exception(
					Error_Codes::VALIDATION_INVALID_VALUE,
					$wp_user_id->get_error_message(),
					null,
					400
				);
			}
		}

		// Store Telegram ID as user meta
		update_user_meta( $wp_user_id, 'telegram_user_id', $telegram_id );

		// Fetch and save avatar from Telegram
		$this->fetch_and_save_avatar( $wp_user_id, (int) $telegram_id, $config );

		// Create chatbot user
		$chatbot_user = $this->create_chatbot_user( $wp_user_id, $telegram_id, $config );

		return $chatbot_user;
	}

	/**
	 * Gets a chatbot user by Telegram ID using device_uuid.
	 *
	 * The device_uuid stores the Telegram user agent as 'telegram-{telegram_id}'.
	 *
	 * @param string $telegram_id Telegram user ID.
	 * @param Config $config      Config object.
	 *
	 * @return Chatbot_User|null
	 * @since 1.0.11
	 */
	public function get_chatbot_user_by_telegram_id( string $telegram_id, Config $config ): ?Chatbot_User {
		$device_uuid = 'telegram-' . $telegram_id;

		// Find chatbot users by device_uuid (user agent)
		$chatbot_users = Chatbot_User::where( [
			'device_uuid' => $device_uuid,
			'type'        => Chatbot_User::TYPE_AGENT,
		] );

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

		if ( ! is_array( $chatbot_users ) && method_exists( $chatbot_users, 'get' ) ) {
			$chatbot_users = $chatbot_users->get();
		}

		// Iterate through users to find one with the correct config ID
		foreach ( $chatbot_users as $chatbot_user ) {
			if ( ! $chatbot_user instanceof Chatbot_User ) {
				continue;
			}

			// Verify it's associated with the correct config
			$live_agent_config_id = $chatbot_user->get_meta( 'live_agent_config_id' );

			// If config ID matches or is missing (legacy?), return it
			if ( ! $live_agent_config_id || $live_agent_config_id == $config->get_id() ) {
				return $chatbot_user;
			}
		}

		return null;
	}

	/**
	 * Creates a chatbot user.
	 *
	 * @param int    $wp_user_id  WordPress user ID.
	 * @param string $telegram_id Telegram user ID.
	 * @param Config $config      Config object.
	 *
	 * @return Chatbot_User
	 * @throws \Exception
	 * @since 1.0.11
	 */
	private function create_chatbot_user( int $wp_user_id, string $telegram_id, Config $config ): Chatbot_User {
		$repository   = new Chatbot_User_Repository();
		$chatbot_user = $repository->create(
			$wp_user_id,
			'0.0.0.0',
			'telegram-' . $telegram_id,
			Chatbot_User::TYPE_AGENT,
			Chatbot_User::STATUS_ACTIVE
		);

		// Store Telegram user ID as meta
		$chatbot_user->update_meta( 'telegram_user_id', $telegram_id );

		$chatbot_user->update_meta( 'live_agent_config_id', $config->get_id() );

		return $chatbot_user;
	}

	/**
	 * Update agent info if Telegram user info changed.
	 *
	 * @param Chatbot_User $chatbot_user  Chatbot user.
	 * @param array        $telegram_user Telegram user data.
	 * @param Config       $config        Config object.
	 *
	 * @return void
	 * @since 1.0.11
	 */
	private function update_agent_info( Chatbot_User $chatbot_user, array $telegram_user, Config $config ): void {
		$wp_user_id = $chatbot_user->get_wp_user_id();

		if ( ! $wp_user_id ) {
			return;
		}

		$first_name   = $telegram_user['first_name'] ?? '';
		$last_name    = $telegram_user['last_name'] ?? '';
		$display_name = trim( $first_name . ' ' . $last_name );
		$telegram_id  = $telegram_user['id'] ?? '';

		if ( $display_name ) {
			wp_update_user( [
				'ID'           => $wp_user_id,
				'first_name'   => $first_name,
				'last_name'    => $last_name,
				'display_name' => $display_name,
			] );
		}

		// Fetch avatar if not already cached
		$existing_avatar = get_user_meta( $wp_user_id, 'telegram_avatar_url', true );

		if ( empty( $existing_avatar ) && ! empty( $telegram_id ) ) {
			$this->fetch_and_save_avatar( $wp_user_id, (int) $telegram_id, $config );
		}
	}

	/**
	 * Generates a unique username.
	 *
	 * @param string $preferred_username Preferred username.
	 *
	 * @return string Unique username.
	 * @since 1.0.11
	 */
	private function generate_unique_username( string $preferred_username ): string {
		$username = sanitize_user( $preferred_username );
		$original = $username;
		$counter  = 1;

		while ( username_exists( $username ) ) {
			$username = $original . $counter;
			$counter++;
		}

		return $username;
	}

	/**
	 * Ensures the agent role exists in WordPress.
	 *
	 * @return void
	 * @since 1.0.11
	 */
	private function ensure_agent_role_exists(): void {
		if ( ! get_role( Chatbot_User::ROLE_AGENT ) ) {
			add_role(
				Chatbot_User::ROLE_AGENT,
				__( 'Agent', 'limb-chatbot' ),
				[
					'read' => true,
				]
			);
		}
	}

	/**
	 * Fetch and save user avatar from Telegram.
	 *
	 * Downloads the avatar from Telegram and saves it to WordPress uploads.
	 *
	 * @param int    $wp_user_id  WordPress user ID.
	 * @param int    $telegram_id Telegram user ID.
	 * @param Config $config      Telegram configuration.
	 *
	 * @return string|null Local avatar URL or null on failure.
	 * @since 1.0.11
	 */
	public function fetch_and_save_avatar( int $wp_user_id, int $telegram_id, Config $config ): ?string {
		try {
			$utility = new Messages_Utility( $config );

			// Step 1: Get user profile photos
			$photos = $utility->get_user_profile_photos( $telegram_id, 0, 1 );

			if ( empty( $photos['total_count'] ) || empty( $photos['photos'][0] ) ) {
				return null;
			}

			// Get the largest photo (last in the array)
			$photo_sizes = $photos['photos'][0];
			$photo = end( $photo_sizes );

			if ( empty( $photo['file_id'] ) ) {
				return null;
			}

			// Step 2: Get file path from file_id
			$file = $utility->endpoint->get_file( $photo['file_id'] );

			if ( empty( $file['file_path'] ) ) {
				return null;
			}

			// Step 3: Get download URL
			$download_url = $utility->endpoint->get_file_url( $file['file_path'] );

			// Step 4: Download and save locally
			$local_url = $this->download_and_cache_avatar( $wp_user_id, $telegram_id, $download_url );

			if ( $local_url ) {
				// Store the local URL as user meta
				update_user_meta( $wp_user_id, 'telegram_avatar_url', $local_url );
			}

			return $local_url;
		} catch ( \Exception $e ) {
			return null;
		}
	}

	/**
	 * Download avatar from URL and save to WordPress uploads.
	 *
	 * @param int    $wp_user_id  WordPress user ID.
	 * @param int    $telegram_id Telegram user ID.
	 * @param string $remote_url  Remote avatar URL.
	 *
	 * @return string|null Local avatar URL or null on failure.
	 * @since 1.0.11
	 */
	private function download_and_cache_avatar( int $wp_user_id, int $telegram_id, string $remote_url ): ?string {
		try {
			// Download image
			$response = wp_remote_get( $remote_url, [ 'timeout' => 30 ] );

			if ( is_wp_error( $response ) ) {
				return null;
			}

			$image_data = wp_remote_retrieve_body( $response );

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

			// Get image type from content-type header
			$content_type = wp_remote_retrieve_header( $response, 'content-type' );
			$extension = $this->get_extension_from_mime_type( $content_type );

			// Include required WordPress files
			require_once ABSPATH . 'wp-admin/includes/file.php';
			require_once ABSPATH . 'wp-admin/includes/image.php';

			$upload_dir = wp_upload_dir();

			$filename = 'telegram-avatar-' . $telegram_id . '-' . time() . '.' . $extension;
			$filepath = $upload_dir['path'] . '/' . $filename;

			// Initialize filesystem
			global $wp_filesystem;
			if ( ! function_exists( 'WP_Filesystem' ) ) {
				require_once ABSPATH . 'wp-admin/includes/file.php';
			}
			WP_Filesystem();

			// Save file
			$save_result = $wp_filesystem->put_contents( $filepath, $image_data, FS_CHMOD_FILE );

			if ( ! $save_result ) {
				return null;
			}

			// Create attachment
			$attachment = [
				'post_mime_type' => $content_type,
				'post_title'     => sanitize_file_name( $filename ),
				'post_content'   => '',
				'post_status'    => 'inherit',
			];

			$attach_id = wp_insert_attachment( $attachment, $filepath );

			if ( is_wp_error( $attach_id ) ) {
				return null;
			}

			$attach_data = wp_generate_attachment_metadata( $attach_id, $filepath );
			wp_update_attachment_metadata( $attach_id, $attach_data );

			// Get and store the URL
			$avatar_url = wp_get_attachment_url( $attach_id );
			update_user_meta( $wp_user_id, 'telegram_avatar_attachment_id', $attach_id );

			return $avatar_url;
		} catch ( \Exception $e ) {
			return null;
		}
	}

	/**
	 * Gets file extension from MIME type.
	 *
	 * @param string $mime_type MIME type.
	 *
	 * @return string File extension.
	 * @since 1.0.11
	 */
	private function get_extension_from_mime_type( string $mime_type ): string {
		$extensions = [
			'image/jpeg' => 'jpg',
			'image/png'  => 'png',
			'image/gif'  => 'gif',
			'image/webp' => 'webp',
		];

		return $extensions[ $mime_type ] ?? 'jpg';
	}
}

