import { z } from 'zod';

// CODING-RULES.md §08: validação Zod no boot (fail-fast). Sem default em prod.
// Em dev, defaults razoáveis facilitam o setup; em prod o Vault Agent injeta tudo.

const NodeEnv = z.enum(['development', 'test', 'staging', 'production']);

export const EnvSchema = z
  .object({
    NODE_ENV: NodeEnv.default('development'),

    // API
    API_PORT: z.coerce.number().int().positive().default(3000),
    API_HOST: z.string().min(1).default('0.0.0.0'),
    API_GLOBAL_PREFIX: z.string().min(1).default('api'),
    API_VERSION: z
      .string()
      .regex(/^v\d+$/)
      .default('v1'),

    // CORS — origens permitidas (Web em dev: http://localhost:4200)
    CORS_ORIGINS: z
      .string()
      .default('http://localhost:4200')
      .transform((s) =>
        s
          .split(',')
          .map((o) => o.trim())
          .filter(Boolean),
      ),

    // Master-login (DEV stub — IdP real virá na próxima sessão)
    MASTER_LOGIN_URL: z.url().default('http://localhost:3000/auth/dev'),
    MASTER_LOGIN_JWT_SECRET: z
      .string()
      .min(32)
      .default('dev_jwt_secret_change_in_prod_use_vault_xxxxx'),
    JWT_ACCESS_EXPIRATION: z.coerce.number().int().positive().default(900),
    JWT_REFRESH_EXPIRATION: z.coerce.number().int().positive().default(2_592_000),

    // Multi-tenancy — workspace de dev (até master-login real entrar)
    DEFAULT_WORKSPACE_ID: z.string().min(1).default('dev-workspace'),

    // Representante fixo de dev — forçado no guard enquanto não há login real
    DEV_REP_CODE: z.coerce.number().int().positive().default(29),
    DEV_EMPRESA_ID: z.coerce.number().int().positive().default(1),

    // Postgres (Prisma virá depois)
    DATABASE_URL: z.string().optional(),
    MIGRATION_DATABASE_URL: z.string().optional(),

    // Valkey / BullMQ (entrarão com filas)
    REDIS_URL: z.url().default('redis://localhost:6379'),

    // MinIO (entrará com uploads)
    S3_ENDPOINT: z.url().optional(),
    S3_REGION: z.string().optional(),
    S3_ACCESS_KEY: z.string().optional(),
    S3_SECRET_KEY: z.string().optional(),
    S3_BUCKET: z.string().optional(),

    // SMTP (Mailpit dev / Resend prod)
    SMTP_HOST: z.string().default('localhost'),
    SMTP_PORT: z.coerce.number().int().positive().default(1025),
    SMTP_FROM: z.email().default('noreply@sar.dev'),

    // Telemetry
    OTEL_SERVICE_NAME: z.string().default('sar-api'),
    OTEL_EXPORTER_OTLP_ENDPOINT: z.url().optional(),
    OTEL_TRACES_SAMPLER: z.string().default('parentbased_traceidratio'),
    OTEL_TRACES_SAMPLER_ARG: z.coerce.number().min(0).max(1).default(1.0),
    SENTRY_DSN: z.string().optional(),

    // Web Push VAPID (C6) — gerado via web-push generateVAPIDKeys()
    VAPID_PUBLIC_KEY: z.string().optional(),
    VAPID_PRIVATE_KEY: z.string().optional(),
    VAPID_CONTACT: z.string().default('mailto:noreply@sar.dev'),

    // Feature flags
    GROWTHBOOK_API_HOST: z.string().optional(),
    GROWTHBOOK_CLIENT_KEY: z.string().optional(),

    // Logger
    LOG_LEVEL: z.enum(['fatal', 'error', 'warn', 'info', 'debug', 'trace']).default('info'),
  })
  .superRefine((env, ctx) => {
    if (env.NODE_ENV === 'production') {
      if (env.MASTER_LOGIN_JWT_SECRET.startsWith('dev_jwt_secret')) {
        ctx.addIssue({
          code: 'custom',
          path: ['MASTER_LOGIN_JWT_SECRET'],
          message:
            'JWT secret de DEV não pode ser usada em produção (CODING-RULES §08, PGD-SEC-002).',
        });
      }
      if (!env.DATABASE_URL) {
        ctx.addIssue({
          code: 'custom',
          path: ['DATABASE_URL'],
          message: 'obrigatório em produção',
        });
      }
    }
  });

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

export function validateEnv(raw: Record<string, unknown>): Env {
  const result = EnvSchema.safeParse(raw);
  if (!result.success) {
    // Fail-fast: agrupa erros legíveis antes do crash.
    const issues = result.error.issues
      .map((i) => `  - ${i.path.join('.') || '(root)'}: ${i.message}`)
      .join('\n');
    throw new Error(`[env] validação falhou — corrija .env:\n${issues}`);
  }
  return result.data;
}
