// src/env.ts
// Strict env validation (Zod) — fail fast, no silent crash in prod.
import { z } from "zod";

const schema = z.object({
  DATABASE_URL: z.string().min(1, "DATABASE_URL is required"),
  // SEC-P1 — optional owner-role connection string for migrations only.
  // Unset (dev/test today): migrate.ts falls back to DATABASE_URL, i.e. the
  // exact behavior before this variable existed. Set in prod once the
  // least-privilege app role exists, so DATABASE_URL (runtime) can point at
  // the DML-only role while migrations still run as the DDL-capable owner.
  // See docs/project/ops/db-least-privilege.md.
  MIGRATION_DATABASE_URL: z.string().optional(),
  // Session signing secret — required, fail fast if missing/weak.
  BETTER_AUTH_SECRET: z
    .string()
    .min(
      32,
      "BETTER_AUTH_SECRET must be at least 32 chars (openssl rand -base64 32)",
    ),
  // Base URL (also read by Better Auth itself); optional — derivable on Vercel.
  BETTER_AUTH_URL: z.string().url().optional(),
  GOOGLE_CLIENT_ID: z.string().optional(),
  GOOGLE_CLIENT_SECRET: z.string().optional(),
  GITHUB_CLIENT_ID: z.string().optional(),
  GITHUB_CLIENT_SECRET: z.string().optional(),
  // Resend — transactional email (verification, magic-link, reset-password).
  // Both optional in local dev; set together to actually send.
  RESEND_API_KEY: z.string().optional(),
  // Verified-domain sender, e.g. "SEO Insight <noreply@elevaseo.com>".
  EMAIL_FROM: z.string().optional(),
  // God-mode allow-list: comma-separated emails granted super-admin access.
  SUPER_ADMIN_EMAILS: z.string().optional(),
  // Cloudflare R2 (S3-compatible) object storage + analytics ETL service.
  // All optional in local dev; set together to enable heavy CSV import.
  // Endpoint is derived: https://<R2_ACCOUNT_ID>.r2.cloudflarestorage.com (region "auto").
  R2_ACCOUNT_ID: z.string().optional(),
  R2_ACCESS_KEY_ID: z.string().optional(),
  R2_SECRET_ACCESS_KEY: z.string().optional(),
  R2_BUCKET: z.string().optional(),
  // Analytics service (Hono) base URL, e.g. http://localhost:8787.
  ANALYTICS_URL: z.string().url().optional(),
  // Shared secret for the analytics service POST /jobs (Bearer). Must match
  // the ANALYTICS_API_KEY env var of the service itself. Unset = no auth sent.
  ANALYTICS_API_KEY: z.string().optional(),
  // Shared secret for the Rust GSC worker → token-broker route. Unset = route off.
  WORKER_API_KEY: z.string().optional(),
  // Stripe billing — all optional in local dev; set all three to enable billing.
  STRIPE_SECRET_KEY: z.string().optional(),
  STRIPE_PUBLISHABLE_KEY: z.string().optional(),
  STRIPE_WEBHOOK_SECRET: z.string().optional(),
  // SE-Ranking Data API — clé PLATEFORME (les crédits sont à notre charge).
  // Unset = feature « Sync SE-Ranking » masquée.
  SERANKING_API_KEY: z.string().optional(),
});

const parsed = schema.parse(process.env);

// Fail closed on Vercel: a production deploy must be able to send email,
// otherwise account verification would silently turn off.
if (process.env.VERCEL && !(parsed.RESEND_API_KEY && parsed.EMAIL_FROM)) {
  throw new Error(
    "RESEND_API_KEY and EMAIL_FROM are required in production (Vercel).",
  );
}

// Fail closed on Vercel: BETTER_AUTH_URL must be set explicitly in production so
// the auth base URL and trustedOrigins never silently fall back to localhost or
// to request-header inference (both flagged as anti-patterns by the Better Auth
// security docs).
if (process.env.VERCEL && !parsed.BETTER_AUTH_URL) {
  throw new Error("BETTER_AUTH_URL is required in production (Vercel).");
}

export const env = {
  ...parsed,
  /** Google social login is available only when both creds are set. */
  googleEnabled: Boolean(
    parsed.GOOGLE_CLIENT_ID && parsed.GOOGLE_CLIENT_SECRET,
  ),
  /** GitHub social login is available only when both creds are set. */
  githubEnabled: Boolean(
    parsed.GITHUB_CLIENT_ID && parsed.GITHUB_CLIENT_SECRET,
  ),
  /**
   * Email sending requires BOTH the Resend key and a verified sender. When
   * unset, local dev skips verification enforcement and logs links instead.
   */
  emailEnabled: Boolean(parsed.RESEND_API_KEY && parsed.EMAIL_FROM),
  /**
   * Stripe billing requires the secret key, the publishable key AND the
   * webhook secret. When unset, the app boots without the Stripe plugin and
   * billing UI degrades (trial rules only).
   */
  stripeEnabled: Boolean(
    parsed.STRIPE_SECRET_KEY &&
      parsed.STRIPE_PUBLISHABLE_KEY &&
      parsed.STRIPE_WEBHOOK_SECRET,
  ),
  /** Heavy CSV import (R2 + analytics service) needs all R2 creds + the service URL. */
  analyticsEnabled: Boolean(
    parsed.R2_ACCOUNT_ID &&
      parsed.R2_ACCESS_KEY_ID &&
      parsed.R2_SECRET_ACCESS_KEY &&
      parsed.R2_BUCKET &&
      parsed.ANALYTICS_URL,
  ),
  /** Sync SE-Ranking (enrichissement bulk) — needs the platform API key. */
  serankingEnabled: Boolean(parsed.SERANKING_API_KEY),
};
