package ai.decompile.ai.service;

import ai.decompile.ai.model.entity.ChatMessage;
import ai.decompile.ai.model.entity.ChatSession;
import ai.decompile.ai.model.repository.ChatMessageRepository;
import ai.decompile.ai.model.repository.ChatSessionRepository;
import ai.decompile.common.exception.NotFoundException;
import ai.decompile.workspace.service.BinaryService;
import java.util.List;
import java.util.Objects;
import java.util.UUID;
import lombok.RequiredArgsConstructor;
import lombok.extern.log4j.Log4j2;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

@Log4j2
@Service
@RequiredArgsConstructor
@ConditionalOnProperty(name = "app.ai.enabled", havingValue = "true", matchIfMissing = true)
public class ChatSessionService {
  private final ChatSessionRepository sessionRepository;
  private final ChatMessageRepository messageRepository;
  private final BinaryService binaryService;
  private final StreamingModelProvider streamingModelProvider;

  @Value("${app.ai.chat.default-model:gemma4:12b}")
  private String defaultModel;

  @Transactional
  public ChatSession createSession(UUID binaryId, UUID projectId, String model) {
    var binary = binaryService.getBinary(binaryId);
    var effectiveModel = Objects.nonNull(model) ? model : defaultModel;
    streamingModelProvider.resolve();

    var session =
        ChatSession.builder()
            .binaryId(binaryId)
            .projectId(projectId)
            .title(binary.getFilename() + " — Chat")
            .chatModel(effectiveModel)
            .build();

    return sessionRepository.save(session);
  }

  @Transactional(readOnly = true)
  public List<ChatSession> getSessions(UUID binaryId) {
    return sessionRepository.findByBinaryIdOrderByUpdatedAtDesc(binaryId);
  }

  @Transactional(readOnly = true)
  public ChatSession getSession(UUID sessionId) {
    return sessionRepository
        .findById(sessionId)
        .orElseThrow(
            () -> new NotFoundException("Chat session with id '" + sessionId + "' not found"));
  }

  @Transactional
  public void deleteSession(UUID sessionId) {
    var session = getSession(sessionId);
    sessionRepository.delete(session);
  }

  @Transactional(readOnly = true)
  public List<ChatMessage> getMessages(UUID sessionId) {
    return messageRepository.findBySessionIdOrderByCreatedAtAsc(sessionId);
  }

  @Transactional(propagation = Propagation.REQUIRES_NEW)
  public void saveMessage(ChatSession session, String role, String content) {
    var msg =
        ChatMessage.builder()
            .session(session)
            .role(role)
            .content(content)
            .tokenCount(AiUtils.estimateTokens(content))
            .build();

    messageRepository.save(msg);
  }
}
