import {
  buildKnownFailureFileIdentity,
  findMatchingKnownFailureEntries,
  loadKnownFailuresConfig,
} from "../known-failures/index.mjs";

export { loadKnownFailuresConfig };

export function applyKnownFailuresToArtifacts(runArtifact, statusArtifact, knownFailures) {
  if (!knownFailures) return { runArtifact, statusArtifact };

  const runEntries = extractRunFileEntries(runArtifact);
  const statusEntries = extractStatusFileEntries(statusArtifact);
  const fileSummaries = new Map();

  for (const entry of [...runEntries, ...statusEntries]) {
    const key = buildKnownFailureFileIdentity(entry.service, entry.type, entry.path);
    if (!fileSummaries.has(key)) {
      fileSummaries.set(key, {
        service: entry.service,
        type: entry.type,
        path: entry.path,
        status: entry.status,
        error: entry.error || null,
        failureDetails: Array.isArray(entry.failureDetails) ? entry.failureDetails : [],
      });
    }
  }

  const matchesByFileKey = new Map();
  const matchedByFailedEntryIds = new Set();

  for (const fileSummary of fileSummaries.values()) {
    const matches = findMatchingKnownFailureEntries(knownFailures, fileSummary);
    if (matches.length === 0) continue;

    const fileKey = buildKnownFailureFileIdentity(
      fileSummary.service,
      fileSummary.type,
      fileSummary.path
    );
    matchesByFileKey.set(fileKey, matches.map((entry) => toArtifactTriageEntry(entry)));
    if (fileSummary.status === "failed") {
      for (const entry of matches) {
        matchedByFailedEntryIds.add(entry.id);
      }
    }
  }

  for (const entry of [...runEntries, ...statusEntries]) {
    const fileKey = buildKnownFailureFileIdentity(entry.service, entry.type, entry.path);
    const matches = matchesByFileKey.get(fileKey) || [];
    if (matches.length === 0) {
      if (entry.status === "failed") {
        setEntryTriage(entry, {
          status: "untriaged",
          entries: [],
        });
      }
      continue;
    }

    setEntryTriage(entry, {
      status: entry.status === "failed" ? "known_failure" : "known_issue_not_reproduced",
      classifications: [...new Set(matches.map((match) => match.classification))].sort(),
      entries: matches,
    });
  }

  const summaryTests = statusArtifact?.tests || runEntries;
  const triageSummary = buildTriageSummary(
    summaryTests,
    knownFailures.entries,
    matchedByFailedEntryIds
  );
  runArtifact.triageSummary = triageSummary;
  if (statusArtifact) {
    statusArtifact.triageSummary = triageSummary;
  }
  return { runArtifact, statusArtifact };
}

function toArtifactTriageEntry(entry) {
  return {
    id: entry.id,
    title: entry.title,
    classification: entry.classification,
    state: entry.state,
    issue: entry.issue,
    description: entry.description,
    whyFailing: entry.whyFailing,
    lastReviewedAt: entry.lastReviewedAt,
  };
}

function buildTriageSummary(tests, entries, matchedEntryIds) {
  const failedTests = tests.filter((test) => test.status === "failed");
  const knownFailedTests = failedTests.filter((test) => test.triage?.status === "known_failure");
  const byClassification = {};

  for (const test of knownFailedTests) {
    for (const classification of test.triage?.classifications || []) {
      byClassification[classification] = (byClassification[classification] || 0) + 1;
    }
  }

  return {
    failed: {
      total: failedTests.length,
      known: knownFailedTests.length,
      untriaged: failedTests.length - knownFailedTests.length,
      byClassification,
    },
    entries: {
      total: entries.length,
      matchedByFailedTests: matchedEntryIds.size,
      unmatched: entries.length - matchedEntryIds.size,
    },
  };
}

function extractRunFileEntries(runArtifact) {
  const entries = [];

  for (const service of runArtifact.services || []) {
    for (const suite of service.suites || []) {
      for (const file of suite.files || []) {
        entries.push({
          target: file,
          service: service.name,
          type: suite.type,
          path: file.path,
          status: file.status,
          error: file.error || null,
          failureDetails: Array.isArray(file.failureDetails) ? file.failureDetails : [],
        });
      }
    }
  }

  return entries;
}

function extractStatusFileEntries(statusArtifact) {
  return statusArtifact?.tests || [];
}

function setEntryTriage(entry, triage) {
  if (entry?.target) {
    entry.target.triage = triage;
    return;
  }
  entry.triage = triage;
}
