import { plainToInstance, Type } from 'class-transformer';
import {
  IsEnum,
  IsNotEmpty,
  IsNumber,
  IsOptional,
  IsString,
  Min,
  Max,
  validateSync,
} from 'class-validator';

enum Environment {
  Development = 'development',
  Production = 'production',
  Test = 'test',
}

class EnvironmentVariables {
  @IsEnum(Environment)
  NODE_ENV: Environment = Environment.Development;

  @Type(() => Number)
  @IsNumber()
  @Min(1)
  @Max(65535)
  APP_PORT = 3000;

  @IsString()
  @IsNotEmpty()
  APP_URL = 'http://172.20.10.59';

  // Datenbank
  @IsString()
  @IsNotEmpty()
  DATABASE_URL!: string;

  @IsString()
  @IsOptional()
  DATABASE_URL_DIRECT?: string;

  // Redis
  @IsString()
  REDIS_HOST = 'redis';

  @Type(() => Number)
  @IsNumber()
  REDIS_PORT = 6379;

  @IsString()
  @IsOptional()
  REDIS_PASSWORD?: string;

  // JWT
  @IsString()
  @IsNotEmpty()
  JWT_PRIVATE_KEY_PATH = '/app/keys/jwt-private.pem';

  @IsString()
  @IsNotEmpty()
  JWT_PUBLIC_KEY_PATH = '/app/keys/jwt-public.pem';

  @IsString()
  JWT_ACCESS_TOKEN_EXPIRY = '15m';

  @IsString()
  JWT_REFRESH_TOKEN_EXPIRY = '7d';

  @IsString()
  JWT_ISSUER = 'insight-platform';

  // Bcrypt
  @Type(() => Number)
  @IsNumber()
  @Min(10)
  @Max(14)
  BCRYPT_COST = 12;

  // Rate Limiting
  @Type(() => Number)
  @IsNumber()
  THROTTLE_TTL = 60000;

  @Type(() => Number)
  @IsNumber()
  THROTTLE_LIMIT = 200;

  // Microsoft Entra ID (Azure AD) SSO - optional
  @IsOptional()
  @IsString()
  AZURE_TENANT_ID?: string;

  @IsOptional()
  @IsString()
  AZURE_CLIENT_ID?: string;

  @IsOptional()
  @IsString()
  AZURE_CLIENT_SECRET?: string;

  @IsOptional()
  @IsString()
  AZURE_REDIRECT_URI?: string;

  // Microsoft 365 Integration (separate Redirect URI fuer Graph-API-Scopes)
  @IsOptional()
  @IsString()
  AZURE_INTEGRATION_REDIRECT_URI?: string;

  // AES-256-GCM Schluessel fuer Token-Verschluesselung (64 Hex-Zeichen = 32 Bytes)
  // Generieren: openssl rand -hex 32
  @IsOptional()
  @IsString()
  INTEGRATION_ENCRYPTION_KEY?: string;
}

export function validateConfig(
  config: Record<string, unknown>,
): EnvironmentVariables {
  const validatedConfig = plainToInstance(EnvironmentVariables, config, {
    enableImplicitConversion: true,
  });
  const errors = validateSync(validatedConfig, {
    skipMissingProperties: false,
  });

  if (errors.length > 0) {
    throw new Error(`Config validation error: ${errors.toString()}`);
  }
  return validatedConfig;
}
