using NewLife.AI.Models;

namespace NewLife.AI.Clients;

/// <summary>AI 对话客户端接口。绑定连接参数，直接执行对话请求，无需每次传入 Options</summary>
/// <remarks>
/// 设计对标 Microsoft.Extensions.AI（MEAI）的 IChatClient，使熟悉 MEAI 的开发者可无缝迁移。
/// 与 <see cref="AiClientDescriptor"/> 的关系：AiClientDescriptor 是无状态的服务商描述与工厂，
/// 通过 <see cref="AiClientDescriptor.Factory"/> 创建已绑定 Endpoint/ApiKey 的 IChatClient 实例。
/// 使用示例：
/// <code>
/// var client = AiClientRegistry.Default.CreateClient("OpenAI", opts);
/// var response = await client.GetResponseAsync(request);
/// Console.WriteLine(response.Text);
/// </code>
/// </remarks>
public interface IChatClient : IDisposable
{
    /// <summary>非流式对话完成。发送请求并一次性返回完整响应</summary>
    /// <param name="request">内部对话请求，含消息列表与生成参数</param>
    /// <param name="cancellationToken">取消令牌</param>
    /// <returns>完整的对话响应</returns>
    Task<IChatResponse> GetResponseAsync(IChatRequest request, CancellationToken cancellationToken = default);

    /// <summary>流式对话完成。逐块返回生成内容</summary>
    /// <param name="request">内部对话请求，含消息列表与生成参数</param>
    /// <param name="cancellationToken">取消令牌</param>
    /// <returns>流式响应块的异步枚举</returns>
    IAsyncEnumerable<IChatResponse> GetStreamingResponseAsync(IChatRequest request, CancellationToken cancellationToken = default);
}

/// <summary>IChatClient 扩展方法。提供常用便捷调用方式</summary>
public static class ChatClientExtensions
{
    /// <summary>非流式对话（消息列表重载）。将消息列表与选项封装为 <see cref="ChatRequest"/> 后调用接口方法</summary>
    /// <param name="client">对话客户端</param>
    /// <param name="messages">消息列表</param>
    /// <param name="options">对话选项</param>
    /// <param name="cancellationToken">取消令牌</param>
    /// <returns>完整的对话响应</returns>
    public static Task<IChatResponse> GetResponseAsync(this IChatClient client, IList<ChatMessage> messages, ChatOptions? options = null, CancellationToken cancellationToken = default)
        => client.GetResponseAsync(ChatRequest.Create(messages, options), cancellationToken);

    /// <summary>流式对话（消息列表重载）。将消息列表与选项封装为 <see cref="ChatRequest"/> 后调用接口方法</summary>
    /// <param name="client">对话客户端</param>
    /// <param name="messages">消息列表</param>
    /// <param name="options">对话选项</param>
    /// <param name="cancellationToken">取消令牌</param>
    /// <returns>流式响应块的异步枚举</returns>
    public static IAsyncEnumerable<IChatResponse> GetStreamingResponseAsync(this IChatClient client, IList<ChatMessage> messages, ChatOptions? options = null, CancellationToken cancellationToken = default)
        => client.GetStreamingResponseAsync(ChatRequest.Create(messages, options, stream: true), cancellationToken);

    /// <summary>发送单条文本消息并获取完整响应（快速模式）。当 EnableThinking 未指定时自动关闭思考，适合标题生成、摘要提取等轻量任务</summary>
    /// <param name="client">对话客户端</param>
    /// <param name="prompt">用户消息文本</param>
    /// <param name="options">对话选项。EnableThinking 为 null 时自动设为 false</param>
    /// <param name="cancellationToken">取消令牌</param>
    /// <returns>完整的对话响应</returns>
    public static Task<IChatResponse> GetResponseAsync(this IChatClient client, String prompt, ChatOptions? options = null, CancellationToken cancellationToken = default)
        => client.GetResponseAsync(ChatRequest.Create([new ChatMessage { Role = "user", Content = prompt }], EnsureFastOptions(options)), cancellationToken);

    /// <summary>发送单条文本消息并获取流式响应</summary>
    /// <param name="client">对话客户端</param>
    /// <param name="prompt">用户消息文本</param>
    /// <param name="options">对话选项</param>
    /// <param name="cancellationToken">取消令牌</param>
    /// <returns>流式响应块的异步枚举</returns>
    public static IAsyncEnumerable<IChatResponse> GetStreamingResponseAsync(this IChatClient client, String prompt, ChatOptions? options = null, CancellationToken cancellationToken = default)
        => client.GetStreamingResponseAsync(ChatRequest.Create([new ChatMessage { Role = "user", Content = prompt }], options, stream: true), cancellationToken);

    /// <summary>非流式对话完成。发送请求并一次性返回完整响应</summary>
    /// <param name="client">对话客户端</param>
    /// <param name="request">内部对话请求，含消息列表与生成参数</param>
    /// <param name="cancellationToken">取消令牌</param>
    /// <returns>完整的对话响应</returns>
    public static Task<IChatResponse> ChatAsync(this IChatClient client, IChatRequest request, CancellationToken cancellationToken = default)
        => client.GetResponseAsync(request, cancellationToken);

    /// <summary>发送单条文本消息并直接返回回复文本（快速模式）。当 EnableThinking 未指定时自动关闭思考，适合标题生成、数据提取等轻量任务</summary>
    /// <param name="client">对话客户端</param>
    /// <param name="prompt">用户消息文本</param>
    /// <param name="options">对话选项。EnableThinking 为 null 时自动设为 false</param>
    /// <param name="cancellationToken">取消令牌</param>
    /// <returns>模型回复文本，失败时返回 null</returns>
    public static async Task<String?> ChatAsync(this IChatClient client, String prompt, ChatOptions? options = null, CancellationToken cancellationToken = default)
        => (await client.GetResponseAsync(ChatRequest.Create([new ChatMessage { Role = "user", Content = prompt }], EnsureFastOptions(options)), cancellationToken).ConfigureAwait(false)).Text;

    /// <summary>以元组形式传入多条消息并直接返回回复文本（快速模式）。当 EnableThinking 未指定时自动关闭思考，适合数据提取等轻量任务</summary>
    /// <param name="client">对话客户端</param>
    /// <param name="messages">消息元组数组，每项为 (role, content)，如 ("system", "你是助手"), ("user", "你好")</param>
    /// <param name="options">对话选项。EnableThinking 为 null 时自动设为 false</param>
    /// <param name="cancellationToken">取消令牌</param>
    /// <returns>模型回复文本，失败时返回 null</returns>
    public static async Task<String?> ChatAsync(this IChatClient client, (String Role, String Content)[] messages, ChatOptions? options = null, CancellationToken cancellationToken = default)
    {
        var chatMessages = new List<ChatMessage>(messages.Length);
        foreach (var (role, content) in messages)
        {
            chatMessages.Add(new ChatMessage { Role = role, Content = content });
        }
        return (await client.GetResponseAsync(ChatRequest.Create(chatMessages, EnsureFastOptions(options)), cancellationToken).ConfigureAwait(false)).Text;
    }

    /// <summary>流式对话完成。逐块返回生成内容</summary>
    /// <param name="client">对话客户端</param>
    /// <param name="request">内部对话请求，含消息列表与生成参数</param>
    /// <param name="cancellationToken">取消令牌</param>
    /// <returns>流式响应块的异步枚举</returns>
    public static IAsyncEnumerable<IChatResponse> StreamChatAsync(this IChatClient client, IChatRequest request, CancellationToken cancellationToken = default)
        => client.GetStreamingResponseAsync(request, cancellationToken);

    /// <summary>流式对话（消息列表重载）。将消息列表与选项封装为 <see cref="ChatRequest"/> 后调用接口方法</summary>
    /// <param name="client">对话客户端</param>
    /// <param name="messages">消息列表</param>
    /// <param name="options">对话选项</param>
    /// <param name="cancellationToken">取消令牌</param>
    /// <returns>流式响应块的异步枚举</returns>
    public static IAsyncEnumerable<IChatResponse> StreamChatAsync(this IChatClient client, IList<ChatMessage> messages, ChatOptions? options = null, CancellationToken cancellationToken = default)
        => client.GetStreamingResponseAsync(ChatRequest.Create(messages, options, stream: true), cancellationToken);

    /// <summary>发送单条文本消息并获取流式响应</summary>
    /// <param name="client">对话客户端</param>
    /// <param name="prompt">用户消息文本</param>
    /// <param name="options">对话选项</param>
    /// <param name="cancellationToken">取消令牌</param>
    /// <returns>流式响应块的异步枚举</returns>
    public static IAsyncEnumerable<IChatResponse> StreamChatAsync(this IChatClient client, String prompt, ChatOptions? options = null, CancellationToken cancellationToken = default)
        => client.GetStreamingResponseAsync(ChatRequest.Create([new ChatMessage { Role = "user", Content = prompt }], options, stream: true), cancellationToken);

    /// <summary>流式对话（消息列表重载）。将消息列表与选项封装为 <see cref="ChatRequest"/> 后调用接口方法</summary>
    /// <param name="client">对话客户端</param>
    /// <param name="messages">消息列表</param>
    /// <param name="options">对话选项</param>
    /// <param name="cancellationToken">取消令牌</param>
    /// <returns>流式响应块的异步枚举</returns>
    public static IAsyncEnumerable<IChatResponse> StreamChatAsync(this IChatClient client, (String Role, String Content)[] messages, ChatOptions? options = null, CancellationToken cancellationToken = default)
    {
        var chatMessages = new List<ChatMessage>(messages.Length);
        foreach (var (role, content) in messages)
        {
            chatMessages.Add(new ChatMessage { Role = role, Content = content });
        }
        return client.GetStreamingResponseAsync(ChatRequest.Create(chatMessages, options), cancellationToken);
    }

    #region OpenAI风格
    /// <summary>非流式对话完成。发送请求并一次性返回完整响应</summary>
    /// <param name="client">对话客户端</param>
    /// <param name="request">内部对话请求，含消息列表与生成参数</param>
    /// <param name="cancellationToken">取消令牌</param>
    /// <returns>完整的对话响应</returns>
    public static Task<IChatResponse> CompleteChatAsync(this IChatClient client, IChatRequest request, CancellationToken cancellationToken = default)
        => client.GetResponseAsync(request, cancellationToken);

    /// <summary>流式对话完成。逐块返回生成内容</summary>
    /// <param name="client">对话客户端</param>
    /// <param name="request">内部对话请求，含消息列表与生成参数</param>
    /// <param name="cancellationToken">取消令牌</param>
    /// <returns>流式响应块的异步枚举</returns>
    public static IAsyncEnumerable<IChatResponse> CompleteChatStreamingAsync(this IChatClient client, IChatRequest request, CancellationToken cancellationToken = default)
        => client.GetStreamingResponseAsync(request, cancellationToken);
    #endregion

    #region Semantic Kernel 风格
    /// <summary>非流式对话完成。发送请求并一次性返回完整响应</summary>
    /// <param name="client">对话客户端</param>
    /// <param name="request">内部对话请求，含消息列表与生成参数</param>
    /// <param name="cancellationToken">取消令牌</param>
    /// <returns>完整的对话响应</returns>
    public static Task<IChatResponse> GetChatMessageContentsAsync(this IChatClient client, IChatRequest request, CancellationToken cancellationToken = default)
        => client.GetResponseAsync(request, cancellationToken);

    /// <summary>流式对话完成。逐块返回生成内容</summary>
    /// <param name="client">对话客户端</param>
    /// <param name="request">内部对话请求，含消息列表与生成参数</param>
    /// <param name="cancellationToken">取消令牌</param>
    /// <returns>流式响应块的异步枚举</returns>
    public static IAsyncEnumerable<IChatResponse> GetStreamingChatMessageContentsAsync(this IChatClient client, IChatRequest request, CancellationToken cancellationToken = default)
        => client.GetStreamingResponseAsync(request, cancellationToken);
    #endregion

    #region Azure OpenAI SDK 风格
    /// <summary>非流式对话完成。发送请求并一次性返回完整响应</summary>
    /// <param name="client">对话客户端</param>
    /// <param name="request">内部对话请求，含消息列表与生成参数</param>
    /// <param name="cancellationToken">取消令牌</param>
    /// <returns>完整的对话响应</returns>
    public static Task<IChatResponse> GetChatCompletionsAsync(this IChatClient client, IChatRequest request, CancellationToken cancellationToken = default)
        => client.GetResponseAsync(request, cancellationToken);

    /// <summary>流式对话完成。逐块返回生成内容</summary>
    /// <param name="client">对话客户端</param>
    /// <param name="request">内部对话请求，含消息列表与生成参数</param>
    /// <param name="cancellationToken">取消令牌</param>
    /// <returns>流式响应块的异步枚举</returns>
    public static IAsyncEnumerable<IChatResponse> GetChatCompletionsStreamingAsync(this IChatClient client, IChatRequest request, CancellationToken cancellationToken = default)
        => client.GetStreamingResponseAsync(request, cancellationToken);
    #endregion

    #region LangChain.NET 风格
    /// <summary>非流式对话完成。发送请求并一次性返回完整响应</summary>
    /// <param name="client">对话客户端</param>
    /// <param name="request">内部对话请求，含消息列表与生成参数</param>
    /// <param name="cancellationToken">取消令牌</param>
    /// <returns>完整的对话响应</returns>
    public static Task<IChatResponse> InvokeAsync(this IChatClient client, IChatRequest request, CancellationToken cancellationToken = default)
        => client.GetResponseAsync(request, cancellationToken);

    /// <summary>流式对话完成。逐块返回生成内容</summary>
    /// <param name="client">对话客户端</param>
    /// <param name="request">内部对话请求，含消息列表与生成参数</param>
    /// <param name="cancellationToken">取消令牌</param>
    /// <returns>流式响应块的异步枚举</returns>
    public static IAsyncEnumerable<IChatResponse> StreamAsync(this IChatClient client, IChatRequest request, CancellationToken cancellationToken = default)
        => client.GetStreamingResponseAsync(request, cancellationToken);
    #endregion

    /// <summary>将客户端包装为 <see cref="ChatClientBuilder"/>，以便链式添加中间件</summary>
    /// <param name="client">当前客户端（将作为管道的最内层）</param>
    /// <returns>以 client 为内层的构建器</returns>
    /// <example>
    /// <code>
    /// var client = new DashScopeProvider()
    ///     .CreateClient(apiKey, "qwen3.5-flash")
    ///     .AsBuilder()
    ///     .UseMcp(mcpProvider)
    ///     .UseFilters(new LogFilter())
    ///     .Build();
    /// </code>
    /// </example>
    public static ChatClientBuilder AsBuilder(this IChatClient client) => new(client);

    #region 辅助
    /// <summary>确保快速模式选项。当 EnableThinking 为 null 时自动设置为 false，跳过耗时的推理阶段</summary>
    /// <param name="options">原始选项，可为 null</param>
    /// <returns>确保 EnableThinking 已设置的选项实例</returns>
    private static ChatOptions EnsureFastOptions(ChatOptions? options)
    {
        if (options == null) return new ChatOptions { EnableThinking = false };
        options.EnableThinking ??= false;
        return options;
    }
    #endregion
}
