package com.pablotj.ai.chat.infrastructure.persistence.repository;

import com.pablotj.ai.chat.domain.model.Conversation;
import com.pablotj.ai.chat.domain.model.ConversationId;
import com.pablotj.ai.chat.domain.model.ConversationStatus;
import com.pablotj.ai.chat.domain.repository.ConversationRepository;
import com.pablotj.ai.chat.infrastructure.persistence.entity.ConversationStatusEntity;
import com.pablotj.ai.chat.infrastructure.persistence.mapper.ConversationEntityMapper;
import java.util.List;
import java.util.Optional;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Repository;
import org.springframework.transaction.annotation.Transactional;

/**
 * JPA implementation of the ConversationRepository.
 * Handles the persistence of conversation aggregates using JPA entities.
 */
@Repository
@Transactional
public class JpaConversationRepository implements ConversationRepository {

    private static final Logger logger = LoggerFactory.getLogger(JpaConversationRepository.class);

    private final ConversationJpaRepository jpaRepository;
    private final ConversationEntityMapper entityMapper;

    public JpaConversationRepository(
            ConversationJpaRepository jpaRepository,
            ConversationEntityMapper entityMapper) {
        this.jpaRepository = jpaRepository;
        this.entityMapper = entityMapper;
    }

    @Override
    public Conversation save(Conversation conversation) {
        logger.debug("Saving conversation: {}", conversation.getConversationId());

        var entity = entityMapper.toEntity(conversation);
        var savedEntity = jpaRepository.save(entity);
        var savedConversation = entityMapper.toDomain(savedEntity);

        logger.debug("Successfully saved conversation: {}", savedConversation.getConversationId());

        return savedConversation;
    }

    @Override
    @Transactional(readOnly = true)
    public Optional<Conversation> findById(ConversationId conversationId) {
        logger.debug("Finding conversation by ID: {}", conversationId);

        return jpaRepository.findByUuid(conversationId.getUuid())
                .map(entityMapper::toDomain);
    }

    @Override
    @Transactional(readOnly = true)
    public List<Conversation> findByStatus(ConversationStatus status) {
        logger.debug("Finding conversations by status: {}", status);

        ConversationStatusEntity entityStatus = entityMapper.toEntityStatus(status);

        return jpaRepository.findByStatusOrderByCreatedAtDesc(entityStatus)
                .stream()
                .map(entityMapper::toDomain)
                .toList();
    }

    @Override
    @Transactional(readOnly = true)
    public List<Conversation> findAllActiveOrderedByCreationDate() {
        logger.debug("Finding all active conversations ordered by creation date");

        return jpaRepository.findActiveConversationsOrderedByCreationDate(ConversationStatusEntity.ACTIVE)
                .stream()
                .map(entityMapper::toDomain)
                .toList();
    }

    @Override
    @Transactional(readOnly = true)
    public boolean existsById(ConversationId conversationId) {
        return jpaRepository.existsByUuid(conversationId.getUuid());
    }

    @Override
    public void deleteById(ConversationId conversationId) {
        logger.debug("Deleting conversation: {}", conversationId);

        jpaRepository.deleteByUuid(conversationId.getUuid());

        logger.debug("Successfully deleted conversation: {}", conversationId);
    }

    @Override
    @Transactional(readOnly = true)
    public long count() {
        return jpaRepository.count();
    }

    @Override
    @Transactional(readOnly = true)
    public long countByStatus(ConversationStatus status) {
        ConversationStatusEntity entityStatus = entityMapper.toEntityStatus(status);
        return jpaRepository.countByStatus(entityStatus);
    }
}
