// Responsibility: fail-closed delivery authority and safe navigation for the retired branch-follower surface.
import {
  pacManualReleaseFix,
  pacNodeReadOnlyNext,
  resolveCicdDeliveryAuthority,
  type CicdDeliveryAuthority,
} from "./cicd-delivery-authority";
import type { BranchFollowerRegistry, FollowerSpec, ParsedOptions } from "./cicd-types";

export type BranchFollowerDeliveryAuthority =
  | {
      readonly kind: "retired-readonly";
      readonly mutationHintsAllowed: false;
      readonly followers: readonly string[];
      readonly pacAuthorities: readonly Extract<CicdDeliveryAuthority, { kind: "pac-pr-merge" }>[];
      readonly reason: "all-selected-followers-retired-to-pac";
    }
  | {
      readonly kind: "legacy-manual";
      readonly mutationHintsAllowed: true;
      readonly followers: readonly string[];
      readonly reason: "all-selected-followers-explicit-legacy-manual";
    }
  | {
      readonly kind: "unknown";
      readonly mutationHintsAllowed: false;
      readonly followers: readonly string[];
      readonly reason: "authority-not-declared" | "authority-mixed" | "retired-pac-identity-invalid" | "legacy-conflicts-with-pac";
      readonly details: readonly Record<string, unknown>[];
    };

export function branchFollowerDeliveryAuthority(
  registry: BranchFollowerRegistry,
  options: ParsedOptions,
): BranchFollowerDeliveryAuthority {
  const followers = selectedFollowers(registry, options);
  const rows = followers.map(resolveFollowerAuthority);
  if (rows.every((row) => row.kind === "retired-readonly")) {
    return {
      kind: "retired-readonly",
      mutationHintsAllowed: false,
      followers: followers.map((follower) => follower.id),
      pacAuthorities: rows.map((row) => row.pacAuthority).filter((item): item is Extract<CicdDeliveryAuthority, { kind: "pac-pr-merge" }> => item !== null),
      reason: "all-selected-followers-retired-to-pac",
    };
  }
  if (rows.every((row) => row.kind === "legacy-manual")) {
    return {
      kind: "legacy-manual",
      mutationHintsAllowed: true,
      followers: followers.map((follower) => follower.id),
      reason: "all-selected-followers-explicit-legacy-manual",
    };
  }
  const reason = rows.some((row) => row.reason === "retired-pac-identity-invalid")
    ? "retired-pac-identity-invalid"
    : rows.some((row) => row.reason === "legacy-conflicts-with-pac")
      ? "legacy-conflicts-with-pac"
      : rows.some((row) => row.kind === "unknown")
        ? "authority-not-declared"
        : "authority-mixed";
  return {
    kind: "unknown",
    mutationHintsAllowed: false,
    followers: followers.map((follower) => follower.id),
    reason,
    details: rows.map((row) => ({ follower: row.follower, kind: row.kind, reason: row.reason, authority: row.pacAuthority })),
  };
}

export function branchFollowerMutationGuard(
  registry: BranchFollowerRegistry,
  options: ParsedOptions,
): Record<string, unknown> | null {
  const deliveryMutation = options.action === "apply"
    || options.action === "run-once"
    || options.action === "job"
    || options.action === "gate"
    || (options.action === "debug-step" && options.debugStep === "state-write");
  const retiredCleanup = options.action === "cleanup-state";
  if (!deliveryMutation && !retiredCleanup) return null;

  const authority = branchFollowerDeliveryAuthority(registry, options);
  if (deliveryMutation && authority.kind === "legacy-manual" && options.scope === "legacy-cicd") return null;
  if (retiredCleanup && authority.kind === "retired-readonly" && options.scope === "retired-maintenance") return null;

  return {
    ok: false,
    action: options.action,
    mutation: false,
    mode: authority.kind === "retired-readonly"
      ? "retired-branch-follower-mutation-blocked"
      : authority.kind === "legacy-manual"
        ? "legacy-branch-follower-scope-required"
        : "branch-follower-delivery-authority-unknown",
    reason: retiredCleanup
      ? "退役状态清理只允许通过 retired-maintenance scoped command；默认入口不修改控制器状态。"
      : "该 branch-follower 已退役或 authority 无法唯一确认；CLI 不执行交付写操作。",
    deliveryAuthority: authority,
    next: branchFollowerReadOnlyNext(registry, options, authority),
    valuesPrinted: false,
  };
}

export function branchFollowerReadOnlyNext(
  registry: BranchFollowerRegistry,
  options: ParsedOptions,
  authority = branchFollowerDeliveryAuthority(registry, options),
): Record<string, unknown> {
  const suffix = options.followerId === null ? "" : ` --follower ${options.followerId}`;
  const nodes = authority.kind === "retired-readonly"
    ? Array.from(new Set(authority.pacAuthorities.map((item) => item.consumer.node)))
    : [];
  const followerNext = {
    status: `bun scripts/cli.ts cicd branch-follower status${suffix}`,
    events: `bun scripts/cli.ts cicd branch-follower events${suffix}`,
    logs: `bun scripts/cli.ts cicd branch-follower logs${suffix}`,
    fixManualRelease: authority.kind === "unknown"
      ? pacManualReleaseFix(authorityFromUnknown(authority))
      : { reference: "docs/reference/platform-infra.md#gitea-与-pipelines-as-code-边界", mutation: false },
    valuesPrinted: false,
  };
  if (nodes.length !== 1) return followerNext;
  const pacNext = pacNodeReadOnlyNext(nodes[0] as string);
  return {
    ...followerNext,
    pacStatus: pacNext.status,
    pacHistory: pacNext.history,
  };
}

function selectedFollowers(registry: BranchFollowerRegistry, options: ParsedOptions): FollowerSpec[] {
  const selected = options.followerId === null
    ? registry.followers
    : registry.followers.filter((follower) => follower.id === options.followerId);
  if (selected.length === 0) throw new Error(`unknown follower ${options.followerId ?? "-"}`);
  return selected;
}

function resolveFollowerAuthority(follower: FollowerSpec): {
  follower: string;
  kind: "retired-readonly" | "legacy-manual" | "unknown";
  reason: string;
  pacAuthority: Extract<CicdDeliveryAuthority, { kind: "pac-pr-merge" }> | null;
} {
  const pacAuthority = resolveCicdDeliveryAuthority({
    node: follower.target.node,
    lane: follower.target.lane,
    sourceRepository: follower.source.repository,
    sourceBranch: follower.source.branch,
  });
  if (follower.deliveryAuthority === "retired-readonly") {
    return pacAuthority.kind === "pac-pr-merge"
      ? { follower: follower.id, kind: "retired-readonly", reason: "exact-pac-consumer", pacAuthority }
      : { follower: follower.id, kind: "unknown", reason: "retired-pac-identity-invalid", pacAuthority: null };
  }
  if (follower.deliveryAuthority === "legacy-manual") {
    return pacAuthority.kind === "pac-pr-merge"
      ? { follower: follower.id, kind: "unknown", reason: "legacy-conflicts-with-pac", pacAuthority }
      : { follower: follower.id, kind: "legacy-manual", reason: "explicit-legacy-manual", pacAuthority: null };
  }
  return { follower: follower.id, kind: "unknown", reason: "authority-not-declared", pacAuthority: null };
}

function authorityFromUnknown(authority: Extract<BranchFollowerDeliveryAuthority, { kind: "unknown" }>): Extract<CicdDeliveryAuthority, { kind: "unknown" }> {
  return {
    kind: "unknown",
    migrated: false,
    mutationHintsAllowed: false,
    consumer: null,
    reason: "authority-identity-mismatch",
    detail: authority.reason,
    configRefs: ["config/cicd-branch-followers.yaml", "config/platform-infra/pipelines-as-code.yaml"],
    valuesPrinted: false,
  };
}
