using Health.Domain.Entities;
using Health.Domain.Enums;

namespace Health.Application.AI;

public sealed class AiConversationService(IAiConversationRepository conversations) : IAiConversationService
{
    private readonly IAiConversationRepository _conversations = conversations;

    public async Task<OpenConversationResult> OpenAsync(
        Guid userId,
        Guid? conversationId,
        AgentType agentType,
        string firstMessage,
        CancellationToken ct)
    {
        if (conversationId.HasValue)
        {
            var existing = await _conversations.GetOwnedAsync(userId, conversationId.Value, ct);
            return existing == null
                ? new OpenConversationResult(false, false, conversationId.Value)
                : new OpenConversationResult(true, false, existing.Id);
        }

        var conversation = new Conversation
        {
            Id = Guid.NewGuid(),
            UserId = userId,
            AgentType = agentType,
            Title = firstMessage.Length > 30 ? firstMessage[..30] : firstMessage,
            CreatedAt = DateTime.UtcNow,
            UpdatedAt = DateTime.UtcNow,
        };
        await _conversations.AddConversationAsync(conversation, ct);
        await _conversations.SaveChangesAsync(ct);
        return new OpenConversationResult(true, true, conversation.Id);
    }

    public async Task AddUserMessageAsync(Guid conversationId, string content, CancellationToken ct) =>
        await AddMessageAsync(conversationId, MessageRole.User, content, updateSummary: false, ct);

    public async Task AddAssistantMessageAsync(Guid conversationId, string content, CancellationToken ct) =>
        await AddMessageAsync(conversationId, MessageRole.Assistant, content, updateSummary: true, ct);

    public async Task<IReadOnlyList<AiConversationMessageDto>> GetRecentMessagesAsync(Guid conversationId, int limit, CancellationToken ct)
    {
        var messages = await _conversations.GetRecentMessagesAsync(conversationId, limit, ct);
        return messages.OrderBy(m => m.CreatedAt).Select(ToMessageDto).ToList();
    }

    public async Task<IReadOnlyList<AiConversationDto>> ListAsync(Guid userId, CancellationToken ct)
    {
        var conversations = await _conversations.ListAsync(userId, ct);
        return conversations.Select(ToDto).ToList();
    }

    public async Task<IReadOnlyList<AiConversationMessageDto>> GetMessagesAsync(Guid userId, Guid conversationId, CancellationToken ct)
    {
        var conversation = await _conversations.GetOwnedAsync(userId, conversationId, ct);
        if (conversation == null) return [];

        var messages = await _conversations.GetMessagesAsync(conversationId, ct);
        return messages.Select(ToMessageDto).ToList();
    }

    public async Task DeleteAsync(Guid userId, Guid conversationId, CancellationToken ct)
    {
        var conversation = await _conversations.GetOwnedAsync(userId, conversationId, ct);
        if (conversation == null) return;

        _conversations.Delete(conversation);
        await _conversations.SaveChangesAsync(ct);
    }

    private async Task AddMessageAsync(Guid conversationId, MessageRole role, string content, bool updateSummary, CancellationToken ct)
    {
        var conversation = await _conversations.GetAsync(conversationId, ct)
            ?? throw new InvalidOperationException("会话不存在");
        await _conversations.AddMessageAsync(new ConversationMessage
        {
            Id = Guid.NewGuid(),
            ConversationId = conversationId,
            Role = role,
            Content = content,
            CreatedAt = DateTime.UtcNow,
        }, ct);

        conversation.MessageCount++;
        conversation.UpdatedAt = DateTime.UtcNow;
        if (updateSummary)
            conversation.Summary = content.Length > 100 ? content[..100] : content;
        await _conversations.SaveChangesAsync(ct);
    }

    private static AiConversationDto ToDto(Conversation conversation) => new(
        conversation.Id,
        conversation.AgentType.ToString(),
        conversation.Title,
        conversation.Summary,
        conversation.MessageCount,
        conversation.CreatedAt,
        conversation.UpdatedAt);

    private static AiConversationMessageDto ToMessageDto(ConversationMessage message) => new(
        message.Id,
        message.Role.ToString(),
        message.Content,
        message.Intent,
        message.MetadataJson,
        message.CreatedAt);
}
