import { z } from "zod";

/**
 * Build DATABASE_URL from discrete DB_* vars when providers inject them
 * separately (Render, some Railway templates, custom panels).
 */
export function resolveDatabaseUrlFromParts(
  env: Record<string, string | undefined> = process.env,
): string | undefined {
  if (env.DATABASE_URL?.trim()) {
    return env.DATABASE_URL.trim();
  }

  const host = env.DB_HOST?.trim();
  const user = env.DB_USER?.trim();
  const password = env.DB_PASSWORD ?? "";
  const name = env.DB_NAME?.trim();
  const port = (env.DB_PORT ?? "5432").trim();
  if (!host || !user || !name) return undefined;

  const sslRaw = (env.DB_SSL ?? env.SSL ?? "false").toString().toLowerCase();
  const useSsl = sslRaw === "true" || sslRaw === "1" || sslRaw === "require";
  const auth = `${encodeURIComponent(user)}:${encodeURIComponent(password)}`;
  const base = `postgresql://${auth}@${host}:${port}/${name}`;
  return useSsl ? `${base}?sslmode=require` : base;
}

/** Apply composed DATABASE_URL onto process.env before Zod validation. */
export function applyResolvedDatabaseUrl(
  env: NodeJS.ProcessEnv = process.env,
): void {
  if (env.DATABASE_URL?.trim()) return;
  const composed = resolveDatabaseUrlFromParts(env);
  if (composed) {
    env.DATABASE_URL = composed;
  }
}

const envSchema = z.object({
  NODE_ENV: z
    .enum(["development", "test", "production"])
    .default("development"),
  APP_NAME: z.string().default("ARCHI"),
  APP_URL: z.string().url().default("http://localhost:3000"),

  PLATFORM_ROOT_DOMAIN: z.string().min(1).default("archi.com"),
  PLATFORM_APP_HOST: z.string().min(1).default("app.archi.com"),
  PLATFORM_ADMIN_HOST: z.string().min(1).default("admin.archi.com"),
  PLATFORM_API_HOST: z.string().min(1).default("api.archi.com"),
  DEV_PLATFORM_HOSTS: z.string().default("localhost:3000,127.0.0.1:3000"),

  DATABASE_URL: z.string().min(1),

  AUTH_SECRET: z.string().min(32),
  AUTH_URL: z.string().url().optional(),
  AUTH_GOOGLE_ID: z.string().optional(),
  AUTH_GOOGLE_SECRET: z.string().optional(),

  STORAGE_PROVIDER: z.enum(["s3", "r2", "local"]).default("local"),
  STORAGE_ENDPOINT: z.string().optional(),
  STORAGE_REGION: z.string().default("auto"),
  STORAGE_BUCKET: z.string().default("archi-media"),
  STORAGE_ACCESS_KEY: z.string().optional(),
  STORAGE_SECRET_KEY: z.string().optional(),
  STORAGE_PUBLIC_BASE_URL: z.string().optional(),

  REDIS_URL: z.string().optional(),

  EMAIL_PROVIDER: z.enum(["console", "resend", "smtp"]).default("console"),
  EMAIL_FROM: z.string().email().default("no-reply@archi.com"),
  EMAIL_API_KEY: z.string().optional(),

  PAYMENT_PROVIDER: z.string().optional(),
  PAYMENT_SECRET: z.string().optional(),
  PAYMENT_WEBHOOK_SECRET: z.string().optional(),

  LOG_LEVEL: z.enum(["debug", "info", "warn", "error"]).default("info"),
  SENTRY_DSN: z.string().optional(),
  FEATURE_FLAGS: z.string().default(""),
});

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

let cachedEnv: Env | null = null;

/**
 * Validates and returns process environment.
 * Call only on the server — never import into client components.
 */
export function getEnv(): Env {
  if (cachedEnv) return cachedEnv;

  applyResolvedDatabaseUrl();

  const parsed = envSchema.safeParse(process.env);
  if (!parsed.success) {
    const details = parsed.error.issues
      .map((issue) => `${issue.path.join(".")}: ${issue.message}`)
      .join("; ");
    throw new Error(`Invalid environment configuration: ${details}`);
  }

  if (parsed.data.NODE_ENV === "production" && !parsed.data.AUTH_URL) {
    throw new Error(
      "Invalid environment configuration: AUTH_URL is required in production",
    );
  }

  cachedEnv = parsed.data;
  return cachedEnv;
}

export function getFeatureFlags(): Set<string> {
  const raw = getEnv().FEATURE_FLAGS;
  return new Set(
    raw
      .split(",")
      .map((flag) => flag.trim())
      .filter(Boolean),
  );
}

export function isFeatureEnabled(flag: string): boolean {
  return getFeatureFlags().has(flag);
}
