/**
 * Auth resolution for OpenAI API access.
 *
 * Resolution order:
 * 1. ~/.gstack/openai.json → { "api_key": "sk-..." }
 * 2. OPENAI_API_KEY environment variable
 * 3. null (caller handles guided setup or fallback)
 *
 * When OPENAI_API_KEY is in use AND its value matches an OPENAI_API_KEY entry
 * in the current directory's .env / .env.<NODE_ENV> / .env.local, we disclose
 * the source on stderr before the run. Catches the silent-billing surface
 * reported in #1248: design generation inside someone else's project would
 * silently bill their OpenAI account if their .env was loaded into the shell.
 */

import fs from "fs";
import path from "path";

type ApiKeySource = "config" | "env";

export interface ApiKeyResolution {
  key: string;
  source: ApiKeySource;
  envFile?: string;
  warning?: string;
}

function configPath(): string {
  return path.join(process.env.HOME || "~", ".gstack", "openai.json");
}

function readEnvValue(filePath: string, key: string): string | null {
  let content: string;
  try {
    content = fs.readFileSync(filePath, "utf-8");
  } catch {
    return null;
  }

  for (const line of content.split(/\r?\n/)) {
    const match = line.match(new RegExp(`^\\s*(?:export\\s+)?${key}\\s*=\\s*(.*)\\s*$`));
    if (!match) continue;

    let value = match[1].trim();
    if (
      (value.startsWith('"') && value.endsWith('"')) ||
      (value.startsWith("'") && value.endsWith("'"))
    ) {
      value = value.slice(1, -1);
    }
    return value;
  }

  return null;
}

function matchingCwdEnvFile(key: string, value: string): string | null {
  const candidates = [".env"];
  const nodeEnv = process.env.NODE_ENV;
  if (nodeEnv) candidates.push(`.env.${nodeEnv}`);
  candidates.push(".env.local");

  for (const fileName of candidates) {
    const fileValue = readEnvValue(path.join(process.cwd(), fileName), key);
    if (fileValue === value) return fileName;
  }

  return null;
}

export function resolveApiKeyInfo(): ApiKeyResolution | null {
  // 1. Check ~/.gstack/openai.json
  try {
    const authPath = configPath();
    if (fs.existsSync(authPath)) {
      const content = fs.readFileSync(authPath, "utf-8");
      const config = JSON.parse(content);
      if (config.api_key && typeof config.api_key === "string") {
        return { key: config.api_key, source: "config" };
      }
    }
  } catch {
    // Fall through to env var
  }

  // 2. Check environment variable
  if (process.env.OPENAI_API_KEY) {
    const envFile = matchingCwdEnvFile("OPENAI_API_KEY", process.env.OPENAI_API_KEY);
    const warning = envFile
      ? `Warning: OPENAI_API_KEY matches ${envFile} in the current directory. Design generation may bill that project's OpenAI account. Run $D setup to store a gstack-specific key in ~/.gstack/openai.json.`
      : undefined;
    return { key: process.env.OPENAI_API_KEY, source: "env", envFile: envFile ?? undefined, warning };
  }

  return null;
}

export function resolveApiKey(): string | null {
  return resolveApiKeyInfo()?.key ?? null;
}

export function describeApiKeySource(resolution: ApiKeyResolution): string {
  if (resolution.source === "config") return "~/.gstack/openai.json";
  if (resolution.envFile) return `OPENAI_API_KEY environment variable (matches ${resolution.envFile} in current directory)`;
  return "OPENAI_API_KEY environment variable";
}

/**
 * Save an API key to ~/.gstack/openai.json with 0600 permissions.
 */
export function saveApiKey(key: string): void {
  const dir = path.dirname(configPath());
  fs.mkdirSync(dir, { recursive: true });
  // Create the file owner-only up front so the API key is never briefly
  // world/group-readable in the window between write and chmod. The trailing
  // chmodSync is kept as a backstop to tighten a pre-existing loose file.
  fs.writeFileSync(configPath(), JSON.stringify({ api_key: key }, null, 2), { mode: 0o600 });
  fs.chmodSync(configPath(), 0o600);
}

/**
 * Get API key or exit with setup instructions.
 */
export function requireApiKey(): string {
  const resolution = resolveApiKeyInfo();
  if (!resolution) {
    console.error("No OpenAI API key found.");
    console.error("");
    console.error("Run: $D setup");
    console.error("  or save to ~/.gstack/openai.json: { \"api_key\": \"sk-...\" }");
    console.error("  or set OPENAI_API_KEY environment variable");
    console.error("");
    console.error("Get a key at: https://platform.openai.com/api-keys");
    process.exit(1);
  }
  console.error(`Using OpenAI key from ${describeApiKeySource(resolution)}.`);
  if (resolution.warning) console.error(resolution.warning);
  return resolution.key;
}
