import { z } from 'zod';

const envSchema = z
  .object({
    // Database
    DATABASE_URL: z.string().url().startsWith('postgresql://'),

    // Redis
    REDIS_URL: z.string().url().startsWith('redis://'),

    // Auth
    BETTER_AUTH_SECRET: z.string().min(32),
    BETTER_AUTH_URL: z.string().url(),
    CSRF_SECRET: z.string().min(32),

    // MinIO
    MINIO_ENDPOINT: z.string().min(1),
    MINIO_PORT: z.coerce.number().int().positive(),
    MINIO_ACCESS_KEY: z.string().min(1),
    MINIO_SECRET_KEY: z.string().min(1),
    MINIO_BUCKET: z.string().min(1),
    MINIO_USE_SSL: z.enum(['true', 'false']).transform((v) => v === 'true'),

    // Documenso
    DOCUMENSO_API_URL: z.string().url(),
    DOCUMENSO_API_KEY: z.string().min(1),
    DOCUMENSO_API_VERSION: z.enum(['v1', 'v2']).default('v1'),
    DOCUMENSO_WEBHOOK_SECRET: z.string().min(16),
    DOCUMENSO_TEMPLATE_ID_EOI: z.coerce.number().int().positive().default(8),
    DOCUMENSO_CLIENT_RECIPIENT_ID: z.coerce.number().int().positive().default(192),
    DOCUMENSO_DEVELOPER_RECIPIENT_ID: z.coerce.number().int().positive().default(193),
    DOCUMENSO_APPROVAL_RECIPIENT_ID: z.coerce.number().int().positive().default(194),

    // Email
    SMTP_HOST: z.string().min(1),
    SMTP_PORT: z.coerce.number().int().positive(),
    SMTP_USER: z.string().optional(),
    SMTP_PASS: z.string().optional(),
    SMTP_FROM: z.string().optional(),
    // Dev/test safety net: when set, sendEmail redirects every outbound message
    // to this address regardless of the requested recipient. Leave empty in prod.
    EMAIL_REDIRECT_TO: z.string().email().optional(),

    // Encryption
    EMAIL_CREDENTIAL_KEY: z
      .string()
      .length(64)
      .regex(/^[0-9a-f]+$/i, 'Must be a 64-character hex string'),

    // Google OAuth (optional)
    GOOGLE_CLIENT_ID: z.string().optional(),
    GOOGLE_CLIENT_SECRET: z.string().optional(),

    // Shared secret used by the marketing website's server-side dual-write
    // helper (POST to /api/public/website-inquiries). Set the SAME value on
    // the website's CRM_INTAKE_SECRET env. Leave unset in dev/staging until
    // the website's CRM_INTAKE_URL is also set — without this, the public
    // intake endpoint refuses every request.
    WEBSITE_INTAKE_SECRET: z.string().min(16).optional(),

    // OpenAI (optional)
    OPENAI_API_KEY: z.string().optional(),

    // Sentry (optional — when unset the SDK is a no-op)
    NEXT_PUBLIC_SENTRY_DSN: z.string().url().optional(),
    SENTRY_ENVIRONMENT: z.string().optional(),
    SENTRY_TRACES_SAMPLE_RATE: z.coerce.number().min(0).max(1).default(0.1),

    // App
    APP_URL: z.string().url(),
    PUBLIC_SITE_URL: z.string().url(),
    NODE_ENV: z.enum(['development', 'production', 'test']).default('development'),
    LOG_LEVEL: z.enum(['fatal', 'error', 'warn', 'info', 'debug', 'trace']).default('info'),
    /**
     * HTTP listener port. zod-coerced from PORT so a typo (`PORT=foo`) hard-
     * fails at boot rather than silently listening on an ephemeral port.
     */
    PORT: z.coerce.number().int().positive().default(3000),
    /**
     * When true, the filesystem storage backend refuses to start (per
     * src/lib/storage/filesystem.ts:192). Reading via the zod schema means
     * a typo on the env var hard-fails at boot rather than silently
     * disabling the multi-node guard. Per CLAUDE.md, multi-node deploys
     * MUST use the s3-compatible backend.
     */
    MULTI_NODE_DEPLOYMENT: z
      .enum(['true', 'false'])
      .default('false')
      .transform((v) => v === 'true'),
  })
  .superRefine((env, ctx) => {
    // CRITICAL safety net: EMAIL_REDIRECT_TO is a dev/test feature that
    // silently rewrites every outbound recipient. Leaving it set in prod
    // funnels every customer email (invites, EOIs, portal magic links,
    // contracts) to a single inbox. The audit caught this had only a
    // `logger.debug` line as forensic trail. Refuse boot when both are
    // simultaneously set in production.
    if (env.NODE_ENV === 'production' && env.EMAIL_REDIRECT_TO) {
      ctx.addIssue({
        code: z.ZodIssueCode.custom,
        path: ['EMAIL_REDIRECT_TO'],
        message:
          'EMAIL_REDIRECT_TO must NOT be set in production — it silently rewrites every outbound email recipient. Unset it before deploying.',
      });
    }
  });

export type Env = z.infer<typeof envSchema>;

function validateEnv(): Env {
  if (process.env.SKIP_ENV_VALIDATION === '1') {
    return process.env as unknown as Env;
  }

  const result = envSchema.safeParse(process.env);
  if (!result.success) {
    console.error('Invalid environment variables:');
    for (const issue of result.error.issues) {
      console.error(`  ${issue.path.join('.')}: ${issue.message}`);
    }
    process.exit(1);
  }
  return result.data;
}

export const env = validateEnv();
