using System.ComponentModel.DataAnnotations;
using Journal.Core.Dtos;
using Journal.Core.Models;
using Journal.Core.Repositories;

namespace Journal.Core.Services.Conversations;

public class ConversationService(IConversationRepository repo) : IConversationService
{
    private readonly IConversationRepository _repo = repo ?? throw new ArgumentNullException(nameof(repo));

    private static ConversationDto MapSummary(Conversation c) => new(c.Id, c.Title, c.CreatedAt, c.UpdatedAt);

    private static ConversationMessageDto MapMessage(ConversationMessage m) => new(m.Id, m.Role, m.Text, m.CreatedAt);

    public List<ConversationDto> GetAll()
    {
        var items = _repo.GetAll();
        return [.. items.Select(MapSummary)];
    }

    public ConversationDetailDto? GetById(Guid id)
    {
        var c = _repo.GetById(id);
        if (c is null) return null;

        var messages = _repo.GetMessages(id);
        return new ConversationDetailDto(
            c.Id, c.Title,
            [.. messages.Select(MapMessage)],
            c.CreatedAt, c.UpdatedAt);
    }

    public ConversationDto Create(CreateConversationDto dto)
    {
        ArgumentNullException.ThrowIfNull(dto);
        var ctx = new ValidationContext(dto);
        Validator.ValidateObject(dto, ctx, validateAllProperties: true);

        var conversation = new Conversation(dto.Title);
        _repo.Add(conversation);
        return MapSummary(conversation);
    }

    public bool Update(Guid id, UpdateConversationDto dto)
    {
        ArgumentNullException.ThrowIfNull(dto);
        if (dto.Title is not null && string.IsNullOrWhiteSpace(dto.Title))
            throw new ValidationException("Title cannot be empty");

        return _repo.Update(id, dto.Title?.Trim());
    }

    public bool Remove(Guid id) => _repo.Remove(id);

    public ConversationMessageDto AddMessage(Guid conversationId, string role, string text)
    {
        var message = new ConversationMessage(conversationId, role, text);
        _repo.AddMessage(message);
        return MapMessage(message);
    }

    public List<ConversationMessageDto> GetMessages(Guid conversationId)
    {
        var messages = _repo.GetMessages(conversationId);
        return [.. messages.Select(MapMessage)];
    }
}
