import type { WrnexusPackageManifest } from "./types.ts";

export interface PluginCompatibilityTarget {
  runtime: "bun" | "node" | "edge" | "worker" | "service-worker" | "browser";
  version?: string;
  os?: "win32" | "linux" | "darwin" | string;
  capabilities?: readonly string[];
}

export interface PluginCompatibilityResult {
  target: PluginCompatibilityTarget;
  ok: boolean;
  issues: Array<{
    code:
      | "WRN-PLUGIN-MATRIX-RUNTIME"
      | "WRN-PLUGIN-MATRIX-VERSION"
      | "WRN-PLUGIN-MATRIX-OS"
      | "WRN-PLUGIN-MATRIX-CAPABILITY";
    message: string;
  }>;
}

function parts(version: string): number[] {
  return version
    .replace(/^[^\d]*/, "")
    .split(/[.-]/)
    .slice(0, 3)
    .map((value) => Number(value) || 0);
}

function atLeast(version: string, minimum: string): boolean {
  const left = parts(version);
  const right = parts(minimum);
  for (let index = 0; index < 3; index += 1) {
    if (left[index] !== right[index]) return (left[index] ?? 0) > (right[index] ?? 0);
  }
  return true;
}

export function testPluginCompatibility(
  manifest: WrnexusPackageManifest,
  targets: readonly PluginCompatibilityTarget[],
): PluginCompatibilityResult[] {
  return targets.map((target) => {
    const issues: PluginCompatibilityResult["issues"] = [];
    if (manifest.runtimes?.length && !manifest.runtimes.includes(target.runtime)) {
      issues.push({
        code: "WRN-PLUGIN-MATRIX-RUNTIME",
        message: `${target.runtime} is not declared.`,
      });
    }
    const compatibility = manifest.compatibility;
    if (
      target.runtime === "bun" &&
      target.version &&
      compatibility?.bunMin &&
      !atLeast(target.version, compatibility.bunMin)
    ) {
      issues.push({
        code: "WRN-PLUGIN-MATRIX-VERSION",
        message: `Bun ${target.version} is below ${compatibility.bunMin}.`,
      });
    }
    if (target.os && compatibility?.os?.length && !compatibility.os.includes(target.os)) {
      issues.push({ code: "WRN-PLUGIN-MATRIX-OS", message: `${target.os} is not declared.` });
    }
    const missing = (manifest.requires ?? []).filter(
      (capability) => !target.capabilities?.includes(capability),
    );
    if (missing.length) {
      issues.push({
        code: "WRN-PLUGIN-MATRIX-CAPABILITY",
        message: `Missing: ${missing.join(", ")}.`,
      });
    }
    return { target: { ...target }, ok: issues.length === 0, issues };
  });
}
