const githubRemote =
  /^(?:(https|ssh):\/\/(?:git@)?github\.com\/([A-Za-z0-9-]+)\/([A-Za-z0-9._-]+)|git@github\.com:([A-Za-z0-9-]+)\/([A-Za-z0-9._-]+))$/iu;

/** Strip the single record terminator emitted by a successful command, without normalizing its data. */
export function commandOutput(value: string): string {
  return value.endsWith("\r\n")
    ? value.slice(0, -2)
    : value.endsWith("\n")
      ? value.slice(0, -1)
      : value;
}

/** Parse only documented, unambiguous GitHub HTTPS/SSH/scp repository identities. */
export function canonicalGitHubRepository(value: string): string {
  if (value !== value.trim())
    throw new Error("repository remote must not contain outer whitespace");
  if (/\s/u.test(value)) throw new Error("repository remote must not contain whitespace");
  if (/[\\?#]/u.test(value)) throw new Error("repository remote contains ambiguous syntax");
  if (/%(?:2e|2f|5c)/iu.test(value))
    throw new Error("repository remote contains encoded path syntax");
  if (/^(?:https|ssh):\/\/[^/]*@/iu.test(value) && !/^ssh:\/\/git@github\.com\//iu.test(value))
    throw new Error("repository remote must not contain credentials");
  if (/^(?:https|ssh):\/\/github\.com:/iu.test(value))
    throw new Error("repository remote must not specify a port");

  const withoutSuffix = value.replace(/\.git$/iu, "");
  const match = githubRemote.exec(withoutSuffix);
  if (!match) throw new Error(`unsupported GitHub repository remote: ${value}`);
  const owner = match[2] ?? match[4];
  const repository = match[3] ?? match[5];
  if (
    !owner ||
    !repository ||
    owner === "." ||
    owner === ".." ||
    repository === "." ||
    repository === ".."
  )
    throw new Error("repository remote must not contain dot path segments");
  return `github.com/${owner.toLowerCase()}/${repository.toLowerCase()}`;
}

export interface AuthoritativeRemoteHead {
  readonly branchRef: string;
  readonly oid: string;
}

/** Parse the complete `git ls-remote --symref <remote> HEAD` response without trimming it. */
export function authoritativeRemoteHead(value: string): AuthoritativeRemoteHead {
  const output = commandOutput(value);
  const lines = output.split("\n");
  if (lines.length !== 2)
    throw new Error("remote HEAD response must contain exactly one symref and one OID");
  const symref = /^ref: (refs\/heads\/[^\t\r\n]+)\tHEAD$/u.exec(lines[0]!);
  const oid = /^([0-9a-f]{40}|[0-9a-f]{64})\tHEAD$/u.exec(lines[1]!);
  if (!symref || !oid)
    throw new Error("remote HEAD response is not an authoritative branch and canonical OID");
  return { branchRef: symref[1]!, oid: oid[1]! };
}

export function canonicalRepositoryParts(value: string): {
  readonly host: "github.com";
  readonly owner: string;
  readonly repository: string;
} {
  const [, owner, repository] = canonicalGitHubRepository(value).split("/");
  return { host: "github.com", owner: owner!, repository: repository! };
}
