///////////////////////////////////////////////////////////////////////////////
//
// (C) 2024 ICE TEA GROUP LLC - ALL RIGHTS RESERVED
//
// 
//
// ALL INFORMATION CONTAINED HEREIN IS, AND REMAINS
// THE PROPERTY OF ICE TEA GROUP LLC AND ITS SUPPLIERS, IF ANY.
// THE INTELLECTUAL PROPERTY AND TECHNICAL CONCEPTS CONTAINED
// HEREIN ARE PROPRIETARY TO ICE TEA GROUP LLC AND ITS SUPPLIERS
// AND MAY BE COVERED BY U.S. AND FOREIGN PATENTS, PATENT IN PROCESS, AND
// ARE PROTECTED BY TRADE SECRET OR COPYRIGHT LAW.
//
// DISSEMINATION OF THIS INFORMATION OR REPRODUCTION OF THIS MATERIAL
// IS STRICTLY FORBIDDEN UNLESS PRIOR WRITTEN PERMISSION IS OBTAINED
// FROM ICE TEA GROUP LLC.
//
///////////////////////////////////////////////////////////////////////////////

using System;
using System.ComponentModel;
using System.Net;
using System.Net.Http;
using System.Threading.Tasks;
using Wisej.AI.Helpers;

namespace Wisej.AI.Services
{
	/// <summary>
	/// Represents the base class for web search services, providing common functionality and properties.
	/// </summary>
	/// <remarks>
	/// This abstract class implements the <see cref="IWebSearchService"/> interface and provides a foundation for web search services.
	/// It includes properties for URL configuration, query string formatting, and authentication handling.
	/// </remarks>
	[ApiCategory("Services/WebSearchServiceBase")]
	public abstract class WebSearchServiceBase : IWebSearchService
	{
		private string _url;

		/// <summary>
		/// Initializes a new instance of the <see cref="WebSearchServiceBase"/> class with the specified URL.
		/// </summary>
		/// <param name="url">The base URL for the web search service.</param>
		/// <exception cref="ArgumentNullException">Thrown when the <paramref name="url"/> is null or empty.</exception>
		public WebSearchServiceBase(string url)
		{
			if (url == null || url == "")
				throw new ArgumentNullException(nameof(url));

			_url = url;

			_client = ServiceHelper.GetService<IHttpClientService>();
		}

		#region Properties

		/// <summary>
		/// Gets the base URL for the web search service.
		/// </summary>
		public virtual string Url
			=> _url;

		/// <summary>
		/// Gets or sets the maximum number of sites to search.
		/// </summary>
		[DefaultValue(5)]
		public virtual int MaxSites
		{
			get;
			set;
		} = 5;

		/// <summary>
		/// Gets or sets the query string format.
		/// </summary>
		[DefaultValue("q={0}")]
		public virtual string QueryString
		{
			get;
			set;
		} = "q={0}";

		/// <summary>
		/// Gets the authentication header name.
		/// </summary>
		[DefaultValue("api-key")]
		public virtual string Authentication
		{
			get;
		} = "api-key";

		/// <summary>
		/// Gets or sets the API key used for authentication.
		/// </summary>
		[DefaultValue(null)]
		public string ApiKey
		{
			get => _apiKey;
			set
			{
				_client = null;
				_apiKey = value;
			}
		}
		private string _apiKey;

		/// <summary>
		/// Gets the HTTP client service used for making requests.
		/// </summary>
		/// <remarks>
		/// The client is initialized with a handler that allows automatic redirection and supports various decompression methods.
		/// If an API key is provided, it is added as a default header for authentication.
		/// </remarks>
		internal virtual IHttpClientService Client
		{
			get
			{
				if (!_clientInitialized)
				{
					_clientInitialized = true;

					_client.SetHandler(new HttpClientHandler
					{
						AllowAutoRedirect = true,
#if !NETCOREAPP
						AutomaticDecompression = DecompressionMethods.GZip | DecompressionMethods.Deflate
#else
								AutomaticDecompression = DecompressionMethods.GZip | DecompressionMethods.Deflate | DecompressionMethods.Brotli
#endif
					});

					var apiKey = GetApiKey();
					if (!String.IsNullOrEmpty(apiKey) && !String.IsNullOrEmpty(this.Authentication))
					{
						_client.AddDefaultHeader(this.Authentication, apiKey);
					}
				}

				return _client;
			}
		}
		private bool _clientInitialized;
		private IHttpClientService _client;

		#endregion

		#region Methods

		/// <summary>
		/// Retrieves the API key for the service.
		/// </summary>
		/// <returns>The API key as a string.</returns>
		/// <remarks>
		/// If the <see cref="ApiKey"/> property is not set, this method attempts to retrieve the API key from a centralized store using the service type name.
		/// </remarks>
		protected virtual string GetApiKey()
		{
			return
				!String.IsNullOrEmpty(this.ApiKey)
					? this.ApiKey
					: ApiKeys.GetApiKey(GetType().Name, "SearchService");
		}

		/// <summary>
		/// Performs an asynchronous search with the specified query.
		/// </summary>
		/// <param name="query">The search query string.</param>
		/// <returns>A task representing the asynchronous operation, with a result of the search response as a string.</returns>
		public abstract Task<string> SearchAsync(string query);

		#endregion
	}
}
