/**
 * Tiny semver bumper for resource versions. mcpctl is the source of truth
 * for prompts and skills; their versions are advisory rather than
 * dependency-resolved, so we don't need a full semver library — just patch
 * `0.1.0` → `0.1.1` on every save and let authors bump major/minor when
 * something material changes.
 *
 * Anything that isn't a strict `MAJOR.MINOR.PATCH` (digits-only, three
 * parts) is treated as invalid and replaced with `'0.1.0'`. We don't
 * support pre-release / build-metadata suffixes for resources; if that
 * ever becomes useful we can swap in `semver` from npm without changing
 * call sites.
 */

const SEMVER_RE = /^(\d+)\.(\d+)\.(\d+)$/;

export type BumpKind = 'major' | 'minor' | 'patch';

export function isValidSemver(s: string): boolean {
  return SEMVER_RE.test(s);
}

export function bumpSemver(current: string, kind: BumpKind): string {
  const m = SEMVER_RE.exec(current);
  if (m === null) {
    // Caller passed something we can't parse — start over rather than
    // silently corrupt. Prefer this to throwing because the call path
    // (PromptService.update) would then propagate failure across the
    // entire transaction including the body update.
    return '0.1.0';
  }
  const major = Number(m[1]);
  const minor = Number(m[2]);
  const patch = Number(m[3]);
  switch (kind) {
    case 'major':
      return `${String(major + 1)}.0.0`;
    case 'minor':
      return `${String(major)}.${String(minor + 1)}.0`;
    case 'patch':
      return `${String(major)}.${String(minor)}.${String(patch + 1)}`;
  }
}

/** Compare a < b: returns -1, 0, +1 by major/minor/patch. Invalid → 0. */
export function compareSemver(a: string, b: string): number {
  const ma = SEMVER_RE.exec(a);
  const mb = SEMVER_RE.exec(b);
  if (ma === null || mb === null) return 0;
  for (let i = 1; i <= 3; i++) {
    const ai = Number(ma[i]);
    const bi = Number(mb[i]);
    if (ai !== bi) return ai < bi ? -1 : 1;
  }
  return 0;
}
