package ai.decompile.ai.service.tools;

import ai.decompile.analysis.model.repository.StaticStringRepository;
import java.util.List;
import java.util.Objects;
import lombok.RequiredArgsConstructor;
import lombok.extern.log4j.Log4j2;
import org.springframework.ai.tool.annotation.Tool;
import org.springframework.ai.tool.annotation.ToolParam;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;

@Log4j2
@Component
@RequiredArgsConstructor
@Transactional(readOnly = true)
@ConditionalOnProperty(name = "app.ai.enabled", havingValue = "true", matchIfMissing = true)
@SuppressWarnings("unused")
public class StringTools {
  private final StaticStringRepository stringRepository;
  private final AnalysisResolver analysisResolver;

  private static final int MAX_STRINGS = 30;

  @Tool(
      description =
          """
      Search for strings in the binary. Use this when the user asks about specific
      text patterns — URLs, IP addresses, error messages, registry keys, file paths,
      mutex names, or any hardcoded text.
      Returns up to 30 matching strings with their address, value and encoding.
      """)
  public List<StringResult> searchStrings(
      @ToolParam(
              description =
                  "Text pattern to search for (case-insensitive substring match). "
                      + "Examples: 'http', '192.168', '.exe', 'Error', 'Software\\Microsoft'")
          String pattern,
      @ToolParam(
              description =
                  "The binary ID being analyzed, as shown in the [BINARY OVERVIEW] section.")
          String binaryId) {

    log.debug("searchStrings called: pattern='{}', binaryId={}", pattern, binaryId);

    if (Objects.isNull(pattern) || pattern.isBlank()) {
      return List.of();
    }

    var analysis = analysisResolver.resolve(binaryId);

    if (Objects.isNull(analysis)) {
      return List.of();
    }

    var results =
        stringRepository.searchByValue(analysis.getId(), pattern).stream()
            .limit(MAX_STRINGS)
            .map(s -> new StringResult(s.getAddress(), s.getValue(), s.getEncoding()))
            .toList();

    log.debug("searchStrings: pattern '{}' returned {} results", pattern, results.size());

    return results;
  }

  public record StringResult(String address, String value, String encoding) {}
}
