package ai.decompile.analysis.model.dto;

import ai.decompile.analysis.model.entity.StaticFunction;
import com.fasterxml.jackson.databind.ObjectMapper;
import java.util.Collections;
import java.util.List;
import java.util.Objects;
import java.util.UUID;

public record FunctionDetailResponse(
    UUID id,
    UUID analysisId,
    String name,
    String resolvedName,
    String address,
    int size,
    String flags,
    String assembly,
    String decompiledCode,
    String signature,
    int callerCount,
    int calleeCount,
    List<LabelResponse> labels,
    List<FrameMemberResponse> stackFrame,
    List<CommentResponse> comments,
    List<CfgBlockResponse> cfgBlocks) {
  private static final ObjectMapper MAPPER = new ObjectMapper();

  public static FunctionDetailResponse from(
      StaticFunction f, int callerCount, int calleeCount, List<LabelResponse> labels) {
    return from(f, callerCount, calleeCount, labels, null);
  }

  public static FunctionDetailResponse from(
      StaticFunction f,
      int callerCount,
      int calleeCount,
      List<LabelResponse> labels,
      String resolvedName) {
    return new FunctionDetailResponse(
        f.getId(),
        f.getAnalysis().getId(),
        f.getName(),
        resolvedName,
        f.getAddress(),
        f.getFunctionSize() != null ? f.getFunctionSize() : 0,
        f.getFlags(),
        f.getAssembly(),
        f.getDecompiledCode(),
        f.getSignature(),
        callerCount,
        calleeCount,
        labels,
        parseFrameMembers(f.getStackFrame()),
        parseComments(f.getComments()),
        parseCfgBlocks(f.getCfgBlocks()));
  }

  private static List<FrameMemberResponse> parseFrameMembers(String raw) {
    if (Objects.isNull(raw) || raw.isBlank() || "[]".equals(raw.trim())) {
      return Collections.emptyList();
    }

    try {
      var decoded = MAPPER.readValue("\"" + raw + "\"", String.class);
      return MAPPER.readValue(
          decoded,
          MAPPER.getTypeFactory().constructCollectionType(List.class, FrameMemberResponse.class));
    } catch (Exception e) {
      return Collections.emptyList();
    }
  }

  private static List<CommentResponse> parseComments(String raw) {
    if (Objects.isNull(raw) || raw.isBlank() || "[]".equals(raw.trim())) {
      return Collections.emptyList();
    }

    try {
      var decoded = MAPPER.readValue("\"" + raw + "\"", String.class);
      return MAPPER.readValue(
          decoded,
          MAPPER.getTypeFactory().constructCollectionType(List.class, CommentResponse.class));
    } catch (Exception e) {
      return Collections.emptyList();
    }
  }

  private static List<CfgBlockResponse> parseCfgBlocks(String raw) {
    if (Objects.isNull(raw) || raw.isBlank() || "[]".equals(raw.trim())) {
      return Collections.emptyList();
    }

    try {
      var decoded = MAPPER.readValue("\"" + raw + "\"", String.class);
      return MAPPER.readValue(
          decoded,
          MAPPER.getTypeFactory().constructCollectionType(List.class, CfgBlockResponse.class));
    } catch (Exception e) {
      return Collections.emptyList();
    }
  }
}
