import type { LoaderId, ReleaseManifest } from "./types.ts";
import { ValidationError } from "./validation.ts";

export interface ClientEnvironment {
  launcherVersion: string;
  minecraft: string;
  javaMajor: number;
  loader: LoaderId;
  loaderVersion: string;
  serverProtocol: number;
}

interface ParsedSemver {
  core: [number, number, number];
  prerelease: string[];
}

function parseSemver(value: string): ParsedSemver {
  const match = /^(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)(?:-([0-9A-Za-z.-]+))?(?:\+[0-9A-Za-z.-]+)?$/.exec(value);
  if (!match) throw new ValidationError(`Version launcher invalide: ${value}`);
  return {
    core: [Number(match[1]), Number(match[2]), Number(match[3])],
    prerelease: match[4]?.split(".") ?? [],
  };
}

export function compareSemver(left: string, right: string): number {
  const a = parseSemver(left);
  const b = parseSemver(right);
  for (let index = 0; index < 3; index += 1) {
    const delta = a.core[index]! - b.core[index]!;
    if (delta !== 0) return Math.sign(delta);
  }
  if (a.prerelease.length === 0 || b.prerelease.length === 0) {
    return a.prerelease.length === b.prerelease.length ? 0 : a.prerelease.length === 0 ? 1 : -1;
  }
  const length = Math.max(a.prerelease.length, b.prerelease.length);
  for (let index = 0; index < length; index += 1) {
    const av = a.prerelease[index];
    const bv = b.prerelease[index];
    if (av === undefined || bv === undefined) return av === bv ? 0 : av === undefined ? -1 : 1;
    if (av === bv) continue;
    const an = /^\d+$/.test(av);
    const bn = /^\d+$/.test(bv);
    if (an && bn) return Number(av) < Number(bv) ? -1 : 1;
    if (an !== bn) return an ? -1 : 1;
    return av < bv ? -1 : 1;
  }
  return 0;
}

export function assertCompatible(manifest: ReleaseManifest, environment: ClientEnvironment): void {
  const expected = manifest.payload;
  if (compareSemver(environment.launcherVersion, expected.minimumLauncherVersion) < 0) {
    throw new ValidationError(
      `Launcher ${environment.launcherVersion} trop ancien; version minimale ${expected.minimumLauncherVersion}`,
    );
  }
  if (environment.minecraft !== expected.game.minecraft) {
    throw new ValidationError(`Minecraft ${environment.minecraft} incompatible; attendu ${expected.game.minecraft}`);
  }
  if (!Number.isSafeInteger(environment.javaMajor) || environment.javaMajor < expected.game.javaMajor) {
    throw new ValidationError(`Java ${environment.javaMajor} incompatible; minimum ${expected.game.javaMajor}`);
  }
  if (environment.loader !== expected.game.loader.id || environment.loaderVersion !== expected.game.loader.version) {
    throw new ValidationError(
      `Loader ${environment.loader} ${environment.loaderVersion} incompatible; attendu ${expected.game.loader.id} ${expected.game.loader.version}`,
    );
  }
  if (environment.serverProtocol !== expected.compatibility.serverProtocol) {
    throw new ValidationError(
      `Protocole BG LANDS ${environment.serverProtocol} incompatible; attendu ${expected.compatibility.serverProtocol}`,
    );
  }
}
