/**
 * Storage Configuration
 * File storage and cloud storage settings
 * Sealed namespace for immutability
 */
import { Env } from './env.js';
import { ErrorFactory } from '../exceptions/ZintrustError.js';
import { StartupConfigFile, StartupConfigFileRegistry } from '../runtime/StartupConfigFileRegistry.js';
const hasOwn = (obj, key) => {
    return Object.hasOwn(obj, key);
};
const getStorageDriver = (config, name) => {
    const selected = String(name ?? config.default).trim();
    const diskName = selected === 'default' ? String(config.default).trim() : selected;
    const isExplicitSelection = name !== undefined && String(name).trim().length > 0 && String(name).trim() !== 'default';
    if (diskName !== '' && hasOwn(config.drivers, diskName)) {
        const resolved = config.drivers[diskName];
        if (resolved !== undefined)
            return resolved;
    }
    if (isExplicitSelection) {
        throw ErrorFactory.createConfigError(`Storage disk not configured: ${diskName}`);
    }
    if (Object.keys(config.drivers ?? {}).length === 0) {
        throw ErrorFactory.createConfigError('No storage disks are configured');
    }
    throw ErrorFactory.createConfigError(`Storage default disk not configured: ${diskName || '<empty>'}`);
};
const getDrivers = () => ({
    local: {
        driver: 'local',
        root: Env.get('STORAGE_PATH', 'storage'),
        url: Env.get('STORAGE_URL', '/storage'),
        visibility: Env.get('STORAGE_VISIBILITY', 'private'),
    },
    s3: {
        driver: 's3',
        accessKeyId: Env.get('AWS_ACCESS_KEY_ID', ''),
        secretAccessKey: Env.get('AWS_SECRET_ACCESS_KEY', ''),
        region: Env.AWS_REGION,
        bucket: Env.get('AWS_S3_BUCKET', ''),
        url: Env.get('AWS_S3_URL', ''),
        endpoint: Env.get('AWS_S3_ENDPOINT', ''),
        usePathStyleUrl: Env.getBool('AWS_S3_USE_PATH_STYLE_URL', false),
    },
    r2: {
        driver: 'r2',
        accessKeyId: Env.get('R2_ACCESS_KEY_ID', ''),
        secretAccessKey: Env.get('R2_SECRET_ACCESS_KEY', ''),
        region: Env.get('R2_REGION', ''),
        bucket: Env.get('R2_BUCKET', ''),
        endpoint: Env.get('R2_ENDPOINT', ''),
        url: Env.get('R2_URL', ''),
        binding: Env.get('R2_BINDING', ''),
    },
    gcs: {
        driver: 'gcs',
        projectId: Env.get('GCS_PROJECT_ID', ''),
        keyFile: Env.get('GCS_KEY_FILE', ''),
        bucket: Env.get('GCS_BUCKET', ''),
        url: Env.get('GCS_URL', ''),
    },
});
const createStorageConfig = () => {
    const overrides = StartupConfigFileRegistry.get(StartupConfigFile.Storage) ?? {};
    const storageConfigObj = {
        /**
         * Default storage driver (dynamic; tests may mutate process.env)
         */
        get default() {
            const base = Env.get('STORAGE_CONNECTION', Env.get('STORAGE_DRIVER', 'local'))
                .trim()
                .toLowerCase();
            const selected = overrides.default ?? base;
            return String(selected).trim().toLowerCase();
        },
        /**
         * Storage drivers configuration (dynamic; tests may mutate process.env)
         */
        get drivers() {
            return {
                ...getDrivers(),
                ...overrides.drivers,
            };
        },
        /**
         * Get storage driver config
         */
        getDriver() {
            return getStorageDriver(this);
        },
        /**
         * Get a storage disk configuration by name.
         *
         * - When `name` is provided and not configured, this throws.
         * - When `name` is omitted, it resolves the configured default with a backwards-compatible fallback.
         * - Reserved name `default` aliases the configured default.
         */
        getDriverConfig(name) {
            return getStorageDriver(this, name);
        },
        /**
         * Temporary file settings
         */
        get temp() {
            return {
                path: Env.get('TEMP_PATH', 'storage/temp'),
                maxAge: Env.getInt('TEMP_FILE_MAX_AGE', 86400), // 24 hours
                ...overrides.temp,
            };
        },
        /**
         * Uploads settings
         */
        get uploads() {
            return {
                maxSize: Env.get('MAX_UPLOAD_SIZE', '100mb'),
                allowedMimes: Env.get('ALLOWED_UPLOAD_MIMES', 'jpg,jpeg,png,pdf,doc,docx'),
                path: Env.get('UPLOADS_PATH', 'storage/uploads'),
                ...overrides.uploads,
            };
        },
        /**
         * Backups settings
         */
        get backups() {
            return {
                path: Env.get('BACKUPS_PATH', 'storage/backups'),
                driver: Env.get('BACKUP_DRIVER', 's3'),
                ...overrides.backups,
            };
        },
    };
    return Object.freeze(storageConfigObj);
};
let cached = null;
const proxyTarget = {};
const ensureStorageConfig = () => {
    if (cached)
        return cached;
    cached = createStorageConfig();
    try {
        Object.defineProperties(proxyTarget, Object.getOwnPropertyDescriptors(cached));
    }
    catch {
        // best-effort
    }
    return cached;
};
export const storageConfig = new Proxy(proxyTarget, {
    get(_target, prop) {
        return ensureStorageConfig()[prop];
    },
    ownKeys() {
        ensureStorageConfig();
        return Reflect.ownKeys(proxyTarget);
    },
    getOwnPropertyDescriptor(_target, prop) {
        ensureStorageConfig();
        return Object.getOwnPropertyDescriptor(proxyTarget, prop);
    },
});
