<?php

namespace Limb_Chatbot\Includes\Integrations\Slack\Services;

use Limb_Chatbot\Includes\Data_Objects\Chatbot_User;
use Limb_Chatbot\Includes\Data_Objects\Chatbot_User_Meta;
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\Slack\Utilities\Users_Utility;
use Limb_Chatbot\Includes\Repositories\Chatbot_User_Repository;
use Limb_Chatbot\Includes\Services\Collection;
use Limb_Chatbot\Includes\Utilities\Slack_Users_Utility;

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

	/**
	 * Creates WordPress users and Chatbot users from Slack user data.
	 *
	 * @param  array  $user_ids
	 * @param  Config  $config
	 *
	 * @return Collection collection of created users with status.
	 * @throws Exception
	 * @since 1.0.0
	 */
	public function create_agents_from_slack_users( array $user_ids, Config $config ): Collection {

		$global_utility = new Slack_Users_Utility( $config );
		$utility        = new Users_Utility( $global_utility );
		$slack_users    = $utility->retrieve_multiple( $user_ids );

		if ( empty( $slack_users ) ) {
			throw new Exception( Error_Codes::NOT_FOUND, __( 'No valid Slack users found with provided IDs.', 'limb-chatbot' ), null, 400 );
		}
		if (count($user_ids) !== count($slack_users)){
			throw new Exception( Error_Codes::NOT_FOUND, __( 'One or more ids are invalid.', 'limb-chatbot' ), null, 400 );
		}


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

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

		return $results;
	}

	/**
	 * Creates a single agent from Slack user data.
	 *
	 * @param array $slack_user Slack user object.
	 *
	 * @return Chatbot_User Result with created user IDs.
	 * @throws Exception
	 * @since 1.0.0
	 */
	private function create_single_agent( array $slack_user, Config $config ): ?Chatbot_User {
		$slack_id  = $slack_user['id'] ?? '';
		$email     = $slack_user['profile']['email'] ?? '';

		if ( empty( $slack_id ) || empty( $email ) ) {
			throw new Exception(
				Error_Codes::VALIDATION_INVALID_VALUE,
				__( 'Slack user ID and email are required.', 'limb-chatbot' ),
				null,
				400
			);
		}

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

		// Check if user already exists by email
		$existing_user = get_user_by( 'email', $email );
		if ( $existing_user ) {
			// Check if already has agent role
			if ( ! in_array( Chatbot_User::ROLE_AGENT, $existing_user->roles, true ) ) {
				$existing_user->add_role( Chatbot_User::ROLE_AGENT );
			}

			// Ensure chatbot user exists
			return $this->get_or_create_chatbot_user( $existing_user->ID, $slack_id, $config );
		}

		// Create new WordPress user
		$wp_user_id = $this->create_wp_user( $slack_user );

		// Set avatar from Slack
		$this->set_user_avatar( $wp_user_id, $slack_user );

		// Create chatbot user
		return $this->create_chatbot_user( $wp_user_id, $slack_id, $config );
	}

	/**
	 * Creates a WordPress user from Slack data.
	 *
	 * @param array $slack_user Slack user object.
	 *
	 * @return int WordPress user ID.
	 * @throws Exception
	 * @since 1.0.0
	 */
	private function create_wp_user( array $slack_user ): int {
		$email      = $slack_user['profile']['email'] ?? '';
		$real_name  = $slack_user['real_name'] ?? '';
		$first_name = $slack_user['profile']['first_name'] ?? '';
		$last_name  = $slack_user['profile']['last_name'] ?? '';
		$display_user = $slack_user['profile']['display_name'] ?? $real_name;
		$username   = $slack_user['name'] ?? '';

		// Generate unique username if needed
		$username = $this->generate_unique_username( $username, $email );

		$user_data = [
			'user_login'   => $username,
			'user_email'   => $email,
			'display_name' => $display_user,
			'first_name'   => $first_name,
			'last_name'    => $last_name,
			'role'         => Chatbot_User::ROLE_AGENT,
			'user_pass'    => wp_generate_password( 24, true, true ),
		];

		$user_id = wp_insert_user( $user_data );

		if ( is_wp_error( $user_id ) ) {
			throw new Exception(
				Error_Codes::VALIDATION_INVALID_VALUE,
				$user_id->get_error_message(),
				null,
				400
			);
		}

		// Store Slack ID as user meta
		update_user_meta( $user_id, 'slack_user_id', $slack_user['id'] );

		return $user_id;
	}

	/**
	 * Gets a chatbot user by Slack ID from meta.
	 *
	 * @param string $slack_id Slack user ID.
	 * @param Config $config Config object.
	 *
	 * @return Chatbot_User|null
	 * @since 1.0.0
	 */
	private function get_chatbot_user_by_slack_id( string $slack_id, Config $config ): ?Chatbot_User {
		$chatbot_user_id = Chatbot_User_Meta::where([
			'meta_key' => 'slack_user_id',
			'meta_value' => $slack_id,
		]);
		if ($chatbot_user_id->is_empty()){
			return null;
		}
		$chatbot_user_id = $chatbot_user_id->first()->get_chatbot_user_id();

		// Get the chatbot user
		$chatbot_user = Chatbot_User::where( [ 'id' => $chatbot_user_id, 'type' => Chatbot_User::TYPE_AGENT ] )->first();

		// Verify it's associated with the correct config
		if ( $chatbot_user instanceof Chatbot_User ) {
			$live_agent_config_id = $chatbot_user->get_meta( 'live_agent_config_id' );
			if ( $live_agent_config_id && $live_agent_config_id != $config->get_id() ) {
				// User belongs to a different config, don't return it
				return null;
			}
		}

		return $chatbot_user instanceof Chatbot_User ? $chatbot_user : null;
	}

	/**
	 * Gets or creates a chatbot user for the WordPress user.
	 *
	 * @param int    $wp_user_id WordPress user ID.
	 * @param string $slack_id Slack user ID.
	 *
	 * @return Chatbot_User
	 * @throws \Exception
	 * @since 1.0.0
	 */
	private function get_or_create_chatbot_user( int $wp_user_id, string $slack_id, Config $config): Chatbot_User {
		$chatbot_user = Chatbot_User::where( [ 'wp_user_id' => $wp_user_id, 'type' => Chatbot_User::TYPE_AGENT ] )->first();

		if ( ! $chatbot_user instanceof Chatbot_User ) {
			$chatbot_user = $this->create_chatbot_user( $wp_user_id, $slack_id, $config );
		} else {
			// Update slack_user_id meta if not set or if it doesn't match
			$existing_slack_id = $chatbot_user->get_meta( 'slack_user_id' );
			if ( ! $existing_slack_id ) {
				$chatbot_user->update_meta( 'slack_user_id', $slack_id );
				$chatbot_user->update_meta( 'live_agent_config_id', $config->get_id() );
			} elseif ( $existing_slack_id !== $slack_id ) {
				// If there's a mismatch, this is an error - the same WP user shouldn't have different Slack IDs
				throw new Exception(
					Error_Codes::VALIDATION_INVALID_VALUE,
					sprintf(
						__( 'WordPress user ID %d already has a different Slack ID associated with it.', 'limb-chatbot' ),
						$wp_user_id
					),
					null,
					409
				);
			}
		}

		return $chatbot_user;
	}

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

		// Store Slack user ID as meta
		$chatbot_user->update_meta( 'slack_user_id', $slack_id );
		$chatbot_user->update_meta( 'live_agent_config_id', $config->get_id() );

		return $chatbot_user;
	}

	/**
	 * Sets user avatar from Slack profile image.
	 *
	 * @param int   $user_id WordPress user ID.
	 * @param array $slack_user Slack user object.
	 *
	 * @return void
	 * @since 1.0.0
	 */
	private function set_user_avatar( int $user_id, array $slack_user ): void {
		$avatar_url = $slack_user['profile']['image_original'] ?? $slack_user['profile']['image_512'] ?? '';

		if ( empty( $avatar_url ) ) {
			return;
		}

		try {
			// Download image
			$response = wp_remote_get( $avatar_url, [ 'timeout' => 30 ] );

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

			$image_data = wp_remote_retrieve_body( $response );
			if ( empty( $image_data ) ) {
				return;
			}

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

			// Upload to WordPress
			require_once( ABSPATH . 'wp-admin/includes/file.php' );
			require_once( ABSPATH . 'wp-admin/includes/image.php' );

			$upload_dir = wp_upload_dir();
			$filename   = 'slack-avatar-' . $user_id . '-' . time() . '.' . $extension;
			$filepath   = $upload_dir['path'] . '/' . $filename;

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

			if ( $wp_filesystem->put_contents( $filepath, $image_data, FS_CHMOD_FILE ) ) {
				// 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 ) ) {
					$attach_data = wp_generate_attachment_metadata( $attach_id, $filepath );
					wp_update_attachment_metadata( $attach_id, $attach_data );

					// Store attachment ID and URL as user meta
					$avatar_url = wp_get_attachment_url( $attach_id );
					update_user_meta( $user_id, 'slack_avatar_attachment_id', $attach_id );
					update_user_meta( $user_id, 'slack_avatar_url', $avatar_url );
				}
			}
		} catch ( \Exception $e ) {
			// Silently fail - avatar is not critical
			return;
		}
	}

	/**
	 * Generates a unique username.
	 *
	 * @param string $preferred_username Preferred username.
	 * @param string $email Email address.
	 *
	 * @return string Unique username.
	 * @since 1.0.0
	 */
	private function generate_unique_username( string $preferred_username, string $email ): string {
		$username = sanitize_user( $preferred_username ?: explode( '@', $email )[0] );
		$original = $username;
		$counter  = 1;

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

		return $username;
	}

	/**
	 * Gets file extension from MIME type.
	 *
	 * @param string $mime_type MIME type.
	 *
	 * @return string File extension.
	 * @since 1.0.0
	 */
	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';
	}

	/**
	 * Ensures the agent role exists in WordPress.
	 *
	 * @return void
	 * @since 1.0.0
	 */
	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,
				]
			);
		}
	}
}

