<?php

namespace Limb_Chatbot\Includes\Services;

use Limb_Chatbot\Includes\Data_Objects\Dataset;
use Limb_Chatbot\Includes\Data_Objects\Setting;
use Limb_Chatbot\Includes\Data_Objects\Vector;
use Limb_Chatbot\Includes\Data_Objects\Vector_Index;
use Limb_Chatbot\Includes\Data_Objects\Vector_Index_Vector;
use Limb_Chatbot\Includes\Exceptions\Error_Codes;
use Limb_Chatbot\Includes\Exceptions\Exception;
use Limb_Chatbot\Includes\Repositories\Dataset_Group_Repository;
use Limb_Chatbot\Includes\Services\Collection;
use Limb_Chatbot\Includes\Utilities\Vector_Db_Utility;
use Limb_Chatbot\Includes\Vector_Dbs\Pinecone\Pinecone;

/**
 * Service responsible for dataset group-level updates.
 *
 * Handles bulk status toggles, autosync settings, and placeholder
 * content config handling for grouped datasets.
 */
class Dataset_Group_Service {

	protected Dataset_Group_Repository $repository;

	public function __construct( ?Dataset_Group_Repository $repository = null ) {
		$this->repository = $repository ?? new Dataset_Group_Repository();
	}

	/**
	 * Update one or more dataset groups using payload data.
	 *
	 * @param  array  $payload
	 *
	 * @return array
	 * @throws Exception
	 */
	public function update_groups( array $payload ): array {
		$slugs = $this->normalize_slugs( $payload['slug'] ?? [] );
		if ( empty( $slugs ) ) {
			throw new Exception(
				Error_Codes::VALIDATION_REQUIRED,
				__( 'slug is required and must contain at least one group slug.', 'limb-chatbot' )
			);
		}

		$has_status   = array_key_exists( 'status', $payload );
		$has_autosync = array_key_exists( 'autosync_enabled', $payload );
		$has_content  = array_key_exists( 'content_config', $payload );
		$has_roles    = array_key_exists( 'user_roles', $payload );

		if ( ! $has_status && ! $has_autosync && ! $has_content && ! $has_roles ) {
			throw new Exception(
				Error_Codes::VALIDATION_REQUIRED,
				__( 'At least one update field is required: status, autosync_enabled, content_config, or user_roles.',
					'limb-chatbot' )
			);
		}

		$status           = $has_status ? (int) (bool) $payload['status'] : null;
		$autosync_enabled = $has_autosync ? (int) (bool) $payload['autosync_enabled'] : null;
		$content_config   = $has_content && is_array( $payload['content_config'] ) ? $payload['content_config'] : [];
		$user_roles       = $has_roles && is_array( $payload['user_roles'] ) ? $payload['user_roles'] : [];

		$results = [];

		foreach ( $slugs as $slug ) {
			$group_descriptor = $this->parse_group_slug( $slug );
			$datasets         = $this->get_group_datasets(
				$group_descriptor['source_type'],
				$group_descriptor['source_sub_type']
			);

			$result = [
				'slug'            => $slug,
				'source_type'     => $group_descriptor['source_type'],
				'source_sub_type' => $group_descriptor['source_sub_type'],
				'dataset_count'   => $datasets->count(),
			];

			if ( null !== $status ) {
				$update           = $this->repository->bulk_update_group_status(
					$group_descriptor['source_type'],
					$group_descriptor['source_sub_type'],
					1 === $status
				);
				$result['status'] = $update['enabled'];
			}

			if ( null !== $autosync_enabled ) {
				$update                     = $this->apply_autosync_setting( $group_descriptor, 1 === $autosync_enabled );
				$result['autosync_enabled'] = (int) $update['enabled'];
			}

			if ( $has_content ) {
				$update                   = $this->apply_content_config_placeholder(
					$group_descriptor,
					$content_config
				);
				$result['content_config'] = $update['content_config'];
			}
			if ( $has_roles ) {
				$update                = $this->apply_user_roles_setting( $slug, $user_roles );
				$result['user_roles']  = $update['user_roles'];
			}

			$results[] = $result;
		}

		return [
			'updated' => $results,
		];
	}

	/**
	 * Sanitize and normalize incoming slugs list.
	 *
	 * @param  mixed  $slugs
	 *
	 * @return array
	 */
	private function normalize_slugs( $slugs ): array {
		if ( ! is_array( $slugs ) ) {
			return [];
		}

		$normalized = array_map(
			static function ( $item ) {
				return is_string( $item ) ? trim( sanitize_text_field( $item ) ) : '';
			},
			$slugs
		);
		$normalized = array_filter(
			$normalized,
			static function ( $slug ) {
				return '' !== $slug;
			}
		);

		return array_values( array_unique( $normalized ) );
	}

	/**
	 * Parse group slug into source type/sub type pair.
	 *
	 * @param  string  $slug
	 *
	 * @return array
	 * @throws Exception
	 */
	private function parse_group_slug( string $slug ): array {
		$slug = trim( $slug );

		if ( '' === $slug ) {
			throw new Exception(
				Error_Codes::VALIDATION_INVALID_VALUE,
				__( 'Group slug cannot be empty.', 'limb-chatbot' )
			);
		}

		if ( 'media' === $slug ) {
			return [
				'source_type'     => Dataset::SOURCE_FILE,
				'source_sub_type' => null,
			];
		}

		if ( 'texts' === $slug ) {
			return [
				'source_type'     => Dataset::SOURCE_TEXT,
				'source_sub_type' => null,
			];
		}

		if ( 'q_a' === $slug ) {
			return [
				'source_type'     => Dataset::SOURCE_QA,
				'source_sub_type' => null,
			];
		}

		if ( 'q_a' === $slug ) {
			return [
				'source_type'     => Dataset::SOURCE_QA,
				'source_sub_type' => null,
			];
		}

		if ( preg_match( '/^(post|cpt|url|term|q_a):(.+)$/', $slug, $matches ) ) {
			return [
				'source_type'     => $matches[1],
				'source_sub_type' => rawurldecode( $matches[2] ),
			];
		}

		if ( preg_match( '/^(post|cpt|url|term|q_a)-(.+)$/', $slug, $matches ) ) {
			return [
				'source_type'     => $matches[1],
				'source_sub_type' => rawurldecode( $matches[2] ),
			];
		}

		throw new Exception(
			Error_Codes::VALIDATION_INVALID_VALUE,
			sprintf(
			/* translators: %s is the invalid group slug. */
				__( 'Invalid group slug: %s', 'limb-chatbot' ),
				$slug
			)
		);
	}

	/**
	 * Retrieve datasets matching one group descriptor.
	 *
	 * @param  string  $source_type
	 * @param  string|null  $source_sub_type
	 *
	 * @return Collection
	 */
	private function get_group_datasets( string $source_type, ?string $source_sub_type ): Collection {
		$where = [
			'type'        => Dataset::TYPE_INFORMATIONAL_KNOWLEDGE,
			'source_type' => $source_type,
		];

		if ( null !== $source_sub_type ) {
			$where['source_sub_type'] = $source_sub_type;
		}

		return Dataset::where( $where );
	}

	/**
	 * Update autosync setting for supported source types only.
	 *
	 * @param  array  $group_descriptor
	 * @param  bool  $enabled
	 *
	 * @return array
	 */
	private function apply_autosync_setting( array $group_descriptor, bool $enabled ): array {
		$source_type     = $group_descriptor['source_type'];
		$source_sub_type = $group_descriptor['source_sub_type'];

		if ( ! in_array( $source_type, [ Dataset::SOURCE_POST, Dataset::SOURCE_FILE ], true ) ) {
			return [
				'supported' => 0,
				'updated'   => 0,
				'enabled'   => $enabled ? 1 : 0,
			];
		}

		$key = 'lbaic.utilities.chatbot.auto_sync_for_post_' . $source_sub_type;

		Setting::update(
			[ 'key' => $key ],
			[ 'value' => $enabled ? 1 : 0 ]
		);

		return [
			'supported' => 1,
			'updated'   => 1,
			'enabled'   => $enabled ? 1 : 0,
		];
	}

	/**
	 * Placeholder for future group content-config functionality.
	 *
	 * @param  array  $group_descriptor
	 * @param  array  $content_config
	 *
	 * @return array
	 */
	private function apply_content_config_placeholder( array $group_descriptor, array $content_config ): array {
		$source_type     = $group_descriptor['source_type'];
		$source_sub_type = $group_descriptor['source_sub_type'];

		if ( ! in_array( $source_type, [ Dataset::SOURCE_POST ], true ) ) {
			return [
				'supported'      => 0,
				'updated'        => 0,
				'content_config' => $content_config,
			];
		}

		$key = 'lbaic.utilities.chatbot.content_config_for_' . $source_sub_type;

		Setting::update(
			[ 'key' => $key ],
			[ 'value' => $content_config ]
		);

		return [
			'supported'      => 1,
			'updated'        => 1,
			'content_config' => $content_config,
		];
	}

	/**
	 * Persist group-level user roles setting for the provided slug.
	 *
	 * @param  string  $slug
	 * @param  array  $user_roles
	 *
	 * @return array
	 */
	private function apply_user_roles_setting( string $slug, array $user_roles ): array {
		$key = 'lbaic.utilities.chatbot.user_roles_for_' . $slug;

		Setting::update(
			[ 'key' => $key ],
			[ 'value' => $user_roles ]
		);

		return [
			'updated'    => 1,
			'user_roles' => $user_roles,
		];
	}
}
