/**
 * Resolves the user's Anthropic identity for telemetry.
 *
 * Two paths:
 *   1. OAuth — read accessToken from the `Claude Code-credentials` keychain
 *      entry, call https://api.anthropic.com/api/oauth/profile, return a
 *      stable distinctId = account.uuid + the full profile payload.
 *   2. apiKey — no whoami endpoint exists for Anthropic API keys, so fall
 *      back to the per-install instanceId UUID from settings.json with a
 *      truncated key-prefix as a hint property.
 *
 * Profile resolution is best-effort: any failure (no keychain entry, token
 * expired, network down) returns null and the caller stays on instanceId.
 */
import { spawnSync } from "node:child_process";
import { loadSettings } from "./settings";

const PROFILE_URL = "https://api.anthropic.com/api/oauth/profile";

export type Identity = {
  /** Stable PostHog distinct ID — Anthropic account UUID when we have it, else instanceId. */
  distinctId: string;
  /** Person properties to send via posthog.identify(). */
  properties: Record<string, unknown>;
  /** True iff distinctId came from the OAuth profile (not the instanceId fallback). */
  isOauth: boolean;
};

function readAccessToken(): string | null {
  try {
    const r = spawnSync(
      "security",
      ["find-generic-password", "-s", "Claude Code-credentials", "-w"],
      { encoding: "utf8" },
    );
    if (r.status !== 0) return null;
    const blob = JSON.parse(r.stdout.trim());
    const token = blob?.claudeAiOauth?.accessToken;
    return typeof token === "string" && token.length > 0 ? token : null;
  } catch {
    return null;
  }
}

async function fetchProfile(token: string): Promise<any | null> {
  try {
    const res = await fetch(PROFILE_URL, {
      headers: { Authorization: `Bearer ${token}` },
    });
    if (!res.ok) return null;
    return await res.json();
  } catch {
    return null;
  }
}

/** Synchronous fallback identity — always available, used until OAuth resolves. */
export function instanceIdentity(): Identity {
  const s = loadSettings();
  const props: Record<string, unknown> = {
    auth_mode: s.authMode,
    identity_source: "instance_id",
  };
  if (s.authMode === "apiKey" && s.apiKey) {
    props.api_key_prefix = s.apiKey.slice(0, 8);
  }
  return { distinctId: s.instanceId, properties: props, isOauth: false };
}

/** Async OAuth identity resolution. Returns null when unavailable. */
export async function resolveOauthIdentity(): Promise<Identity | null> {
  const token = readAccessToken();
  if (!token) return null;
  const profile = await fetchProfile(token);
  const accountUuid = profile?.account?.uuid;
  if (!accountUuid) return null;
  const account = profile.account;
  const org = profile.organization ?? {};
  return {
    distinctId: accountUuid,
    isOauth: true,
    properties: {
      identity_source: "oauth_profile",
      auth_mode: "oauth",
      email: account.email,
      name: account.full_name ?? account.display_name,
      account_created_at: account.created_at,
      has_claude_max: account.has_claude_max,
      has_claude_pro: account.has_claude_pro,
      org_uuid: org.uuid,
      org_name: org.name,
      org_type: org.organization_type,
      org_billing_type: org.billing_type,
      org_seat_tier: org.seat_tier,
      org_rate_limit_tier: org.rate_limit_tier,
    },
  };
}
