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

import path from "node:path";
import { bodySha, preview, previewLines, repoParts } from "./auth-and-safety";
import { commandError, githubRequest, isGitHubError, issueBodyReadCommands, validationError } from "./client";
import { repoSummary } from "./repo-compare";
import { ISSUE_LIFECYCLE_PREVIEW_LIMIT } from "./types";
import type { GitHubAuthenticatedUser, GitHubCommandResult, GitHubIssue, GitHubOptions, GitHubRepository, IssueListJsonField } from "./types";

export function issueSummary(issue: GitHubIssue, options: { includeBody?: boolean; includePreview?: boolean; previewLineCount?: number } = {}): Record<string, unknown> {
  const body = issue.body ?? "";
  const includeBody = options.includeBody ?? true;
  const includePreview = options.includePreview ?? true;
  const summary: Record<string, unknown> = {
    id: issue.id,
    number: issue.number,
    title: issue.title,
    state: issue.state,
    closed: issue.state === "closed",
    closedAt: issue.closed_at ?? null,
    url: issue.html_url,
    author: issue.user?.login ?? null,
    createdAt: issue.created_at ?? null,
    updatedAt: issue.updated_at ?? null,
    commentCount: issue.comments ?? null,
    bodyChars: body.length,
    bodySha: bodySha(body),
  };
  if (includeBody) {
    summary.body = body;
  } else {
    summary.bodyOmitted = true;
    summary.fullBodyIncluded = false;
    if (includePreview) {
      summary.bodyPreview = preview(body);
      summary.bodyPreviewLines = previewLines(body, options.previewLineCount ?? 8);
    }
  }
  return summary;
}

export async function repoView(repo: string, token: string): Promise<GitHubCommandResult> {
  const { owner, name } = repoParts(repo);
  const result = await githubRequest<GitHubRepository>(token, "GET", `/repos/${owner}/${name}`);
  if (isGitHubError(result)) return commandError("repo view", repo, result);
  return {
    ok: true,
    command: "repo view",
    repo,
    repository: repoSummary(result),
    request: {
      method: "GET",
      path: `/repos/${owner}/${name}`,
    },
    rest: true,
  };
}

export async function repoCreate(repo: string, token: string, options: GitHubOptions): Promise<GitHubCommandResult> {
  const { owner, name } = repoParts(repo);
  const visibility = options.repoVisibility ?? "private";
  const viewer = options.dryRun ? null : await githubRequest<GitHubAuthenticatedUser>(token, "GET", "/user");
  if (isGitHubError(viewer)) return commandError("repo create", repo, viewer, { phase: "viewer" });
  const viewerLogin = viewer?.login ?? null;
  const createPath = viewerLogin !== null && viewerLogin.toLowerCase() === owner.toLowerCase()
    ? "/user/repos"
    : `/orgs/${owner}/repos`;
  const payload: Record<string, unknown> = {
    name,
    private: visibility === "private",
    auto_init: options.repoAutoInit,
  };
  if (options.repoDescription !== undefined) payload.description = options.repoDescription;
  const planned = {
    repo,
    owner,
    name,
    visibility,
    description: options.repoDescription ?? null,
    autoInit: options.repoAutoInit,
    request: {
      method: "POST",
      path: createPath,
      body: {
        name,
        private: visibility === "private",
        descriptionChars: options.repoDescription?.length ?? 0,
        auto_init: options.repoAutoInit,
      },
    },
  };
  if (options.dryRun) {
    return {
      ok: true,
      command: "repo create",
      repo,
      dryRun: true,
      planned,
      note: "Dry-run only; no GitHub repository was created.",
    };
  }
  const existing = await githubRequest<GitHubRepository>(token, "GET", `/repos/${owner}/${name}`);
  if (!isGitHubError(existing)) {
    return validationError("repo create", repo, "repository already exists; refusing duplicate create", {
      repository: repoSummary(existing),
      planned,
      next: {
        command: `bun scripts/cli.ts gh repo view ${repo}`,
      },
    });
  }
  if (existing.degradedReason !== "repo-not-found") {
    return commandError("repo create", repo, existing, { phase: "preflight-existing-repo", planned });
  }
  const created = await githubRequest<GitHubRepository>(token, "POST", createPath, payload);
  if (isGitHubError(created)) return commandError("repo create", repo, created, { planned });
  return {
    ok: true,
    command: "repo create",
    repo,
    repository: repoSummary(created),
    planned,
    rest: true,
  };
}

export function issueLifecycleSummary(issue: GitHubIssue): Record<string, unknown> {
  return {
    id: issue.id,
    number: issue.number,
    title: issue.title,
    state: issue.state,
    closed: issue.state === "closed",
    closedAt: issue.closed_at ?? null,
    url: issue.html_url,
    author: issue.user?.login ?? null,
    createdAt: issue.created_at ?? null,
    updatedAt: issue.updated_at ?? null,
    commentCount: issue.comments ?? null,
    labels: issueLabelNames(issue),
    bodyChars: (issue.body ?? "").length,
    bodySha: bodySha(issue.body ?? ""),
    bodyOmitted: true,
    fullBodyIncluded: false,
  };
}

export function issueLifecycleDisclosure(repo: string, issueNumber: number, dryRun: boolean): Record<string, unknown> {
  return {
    defaultCompact: true,
    explicitFullDisclosure: false,
    fullBodyIncluded: false,
    bodyOmitted: true,
    dryRunBoundedPreview: dryRun,
    note: "Issue lifecycle write output omits full issue.body; use readCommands.full/raw or gh issue view --json body when full text is needed.",
    readCommands: issueBodyReadCommands(repo, issueNumber),
  };
}

export function issueLifecycleBatchSummary(issues: GitHubIssue[]): Record<string, unknown> {
  const visible = issues.slice(0, ISSUE_LIFECYCLE_PREVIEW_LIMIT);
  return {
    count: issues.length,
    returned: visible.length,
    omitted: Math.max(0, issues.length - visible.length),
    numbers: visible.map((issue) => issue.number),
    issues: visible.map(issueLifecycleSummary),
  };
}

export function labelSummary(label: string | { name?: string; color?: string; description?: string | null }): Record<string, unknown> {
  if (typeof label === "string") return { name: label, color: null, description: null };
  return {
    name: label.name ?? "",
    color: label.color ?? null,
    description: label.description ?? null,
  };
}

export function issueLabelNames(issue: GitHubIssue): string[] {
  return (issue.labels ?? []).map((label) => typeof label === "string" ? label : label.name ?? "").filter((label) => label.length > 0);
}

export function issueListSummary(issue: GitHubIssue, fields: IssueListJsonField[]): Record<string, unknown> {
  const summary: Record<IssueListJsonField, unknown> = {
    number: issue.number,
    title: issue.title,
    state: issue.state,
    closed: issue.state === "closed",
    closedAt: issue.closed_at ?? null,
    url: issue.html_url,
    updatedAt: issue.updated_at ?? null,
    createdAt: issue.created_at ?? null,
    author: issue.user?.login ?? null,
    labels: (issue.labels ?? []).map(labelSummary),
  };
  const selected: Record<string, unknown> = {};
  for (const field of fields) selected[field] = summary[field];
  return selected;
}
