import fs from "fs";
import path from "path";
import { codeFrameColumns } from "@babel/code-frame";
import { createColors } from "picocolors";

const pc = createColors(Boolean(process.stdout?.isTTY || process.env.FORCE_COLOR));

export function findFailureLocation(detail = {}, fallbackError = "") {
  if (detail?.location?.path && Number.isFinite(detail?.location?.line)) {
    return detail.location;
  }

  const stack = detail?.stack || fallbackError;
  if (!stack) return null;
  const match = String(stack).match(/(\/[^\s:()]+):(\d+):(\d+)/);
  if (!match) return null;
  return {
    path: match[1],
    line: Number(match[2]),
    column: Number(match[3]),
  };
}

export function renderCodeFrame(location, options = {}) {
  if (!location?.path || !Number.isFinite(location.line)) return [];
  if (!fs.existsSync(location.path)) return [];

  try {
    const source = fs.readFileSync(location.path, "utf8");
    const frame = codeFrameColumns(
      source,
      {
        start: {
          line: location.line,
          column: Math.max(1, Number(location.column) || 1),
        },
      },
      {
        highlightCode: Boolean(process.stdout?.isTTY || process.env.FORCE_COLOR),
        linesAbove: options.linesAbove ?? 2,
        linesBelow: options.linesBelow ?? 2,
      }
    );
    const label = `${options.label || "code"}: ${formatLocation(location, options.cwd)}`;
    return [pc.bold(label), ...frame.split(/\r?\n/)];
  } catch {
    return [];
  }
}

export function formatLocation(location, cwd = process.cwd()) {
  if (!location?.path || !Number.isFinite(location.line)) return null;
  const relativePath = path.isAbsolute(location.path)
    ? path.relative(cwd, location.path) || path.basename(location.path)
    : location.path;
  return `${relativePath}:${location.line}:${location.column || 1}`;
}
