// SPEC: PJ2026-010606 GitHub入口 draft-2026-06-25-gh-split
// Moved mechanically from scripts/src/gh.ts:5552-5680.

import path from "node:path";
import { bodySafetySignals, bodySha, preview, previewLines, repoParts } from "./auth-and-safety";
import { githubRequest } from "./client";
import type { BodyUpdateMode, GitHubBranch, GitHubCompare, GitHubErrorPayload, GitHubOptions, GitHubRepository } from "./types";

export function repoSummary(repo: GitHubRepository): Record<string, unknown> {
  return {
    id: repo.id ?? null,
    fullName: repo.full_name ?? null,
    private: repo.private ?? null,
    defaultBranch: repo.default_branch ?? null,
    permissions: repo.permissions ?? null,
  };
}

export function branchSummary(branch: GitHubBranch): Record<string, unknown> {
  return {
    name: branch.name ?? null,
    sha: branch.commit?.sha ?? null,
  };
}

export function compareSummary(compare: GitHubCompare): Record<string, unknown> {
  return {
    status: compare.status ?? null,
    aheadBy: compare.ahead_by ?? null,
    behindBy: compare.behind_by ?? null,
    totalCommits: compare.total_commits ?? null,
    htmlUrl: compare.html_url ?? null,
    baseSha: compare.base_commit?.sha ?? null,
    mergeBaseSha: compare.merge_base_commit?.sha ?? null,
  };
}

export function prUrl(repo: string, number: number): string {
  return `https://github.com/${repo}/pull/${number}`;
}

export function encodePathPart(value: string): string {
  return encodeURIComponent(value);
}

export async function repoInfo(token: string, repo: string): Promise<GitHubRepository | GitHubErrorPayload> {
  const { owner, name } = repoParts(repo);
  return githubRequest<GitHubRepository>(token, "GET", `/repos/${owner}/${name}`);
}

export async function branchInfo(token: string, repo: string, branch: string): Promise<GitHubBranch | GitHubErrorPayload> {
  const { owner, name } = repoParts(repo);
  return githubRequest<GitHubBranch>(token, "GET", `/repos/${owner}/${name}/branches/${encodePathPart(branch)}`);
}

export async function compareBranches(token: string, repo: string, base: string, head: string): Promise<GitHubCompare | GitHubErrorPayload> {
  const { owner, name } = repoParts(repo);
  return githubRequest<GitHubCompare>(token, "GET", `/repos/${owner}/${name}/compare/${encodePathPart(base)}...${encodePathPart(head)}`);
}

export function prCreatePlannedOperation(repo: string, options: GitHubOptions, body: string, bodySource: Record<string, unknown>): Record<string, unknown> {
  return {
    repo,
    title: options.title,
    base: options.base,
    head: options.head,
    draft: options.draft,
    bodyChars: body.length,
    bodyPreview: preview(body),
    bodyPreviewLines: body.split(/\r?\n/).slice(0, 12),
    bodySource,
    preservesRawNewlines: body.includes("\n"),
    containsLiteralBackslashN: body.includes("\\n"),
    containsBackticks: body.includes("`"),
    request: {
      method: "POST",
      path: "/repos/{owner}/{repo}/pulls",
      body: {
        title: options.title,
        base: options.base,
        head: options.head,
        draft: options.draft,
        bodyChars: body.length,
      },
    },
    validation: {
      repo: "required",
      base: "required",
      head: "required",
      title: "required",
      body: body.length > 0 ? "optional" : "empty",
    },
  };
}

export function prCommentPlannedOperation(repo: string, issueNumber: number, body: string, bodySource: Record<string, unknown>): Record<string, unknown> {
  return {
    repo,
    issueNumber,
    bodyChars: body.length,
    bodyPreview: preview(body),
    bodyPreviewLines: body.split(/\r?\n/).slice(0, 12),
    bodySource,
    preservesRawNewlines: body.includes("\n"),
    containsLiteralBackslashN: body.includes("\\n"),
    containsBackticks: body.includes("`"),
    request: {
      method: "POST",
      path: `/repos/{owner}/{repo}/issues/${issueNumber}/comments`,
      body: { bodyChars: body.length },
    },
    validation: {
      repo: "required",
      issueNumber: "required",
      body: "required",
    },
  };
}

export function bodyUpdatePlan(command: string, repo: string, number: number, mode: BodyUpdateMode, body: string, bodySource: Record<string, unknown>, existingBody: string | null): Record<string, unknown> {
  const finalBody = mode === "append" ? `${existingBody ?? ""}${body}` : body;
  return {
    command,
    repo,
    number,
    mode,
    bodySource,
    input: bodySafetySignals(body),
    existingBody: existingBody === null ? { fetched: false } : { fetched: true, bodyChars: existingBody.length, bodySha: bodySha(existingBody) },
    finalBody: {
      bodyChars: finalBody.length,
      bodyPreview: preview(finalBody),
      bodyPreviewLines: previewLines(finalBody),
      ...bodySafetySignals(finalBody),
    },
  };
}
