import { Env } from '../../../config/env.js';
import { ErrorFactory } from '../../../exceptions/ZintrustError.js';
import { fsPromises as fs } from '../../../node-singletons/fs.js';
import * as path from '../../../node-singletons/path.js';
import { LocalSignedUrl } from '../LocalSignedUrl.js';
export const LocalDriver = Object.freeze({
    resolveKey(config, key) {
        if (!config.root || config.root.trim() === '') {
            throw ErrorFactory.createConfigError('Local storage root is not configured');
        }
        if (key.trim() === '') {
            throw ErrorFactory.createValidationError('Local storage: key is required');
        }
        if (key.startsWith('/') || key.startsWith('\\')) {
            throw ErrorFactory.createValidationError('Local storage: key must be relative');
        }
        const segments = key.split(/[/\\]+/g);
        if (segments.some((s) => s === '..' || s === '.')) {
            throw ErrorFactory.createValidationError('Local storage: invalid key');
        }
        const fullPath = path.resolve(path.join(config.root, key));
        return fullPath;
    },
    async put(config, key, content) {
        const fullPath = LocalDriver.resolveKey(config, key);
        const dir = path.dirname(fullPath);
        await fs.mkdir(dir, { recursive: true });
        if (typeof content === 'string') {
            await fs.writeFile(fullPath, content, 'utf8');
        }
        else {
            await fs.writeFile(fullPath, content);
        }
        return fullPath;
    },
    async get(config, key) {
        const fullPath = LocalDriver.resolveKey(config, key);
        try {
            return await fs.readFile(fullPath);
        }
        catch (err) {
            throw ErrorFactory.createNotFoundError('Local storage: file not found', { key, error: err });
        }
    },
    async exists(config, key) {
        const fullPath = LocalDriver.resolveKey(config, key);
        try {
            await fs.access(fullPath);
            return true;
        }
        catch {
            return false;
        }
    },
    async delete(config, key) {
        const fullPath = LocalDriver.resolveKey(config, key);
        try {
            await fs.unlink(fullPath);
        }
        catch {
            // ignore not found
        }
    },
    url(config, key) {
        if (config?.url === undefined || config.url.trim() === '')
            return undefined;
        return `${config.url.replace(/\/$/, '')}/${key}`;
    },
    tempUrl(config, key, options) {
        if (options?.method === 'PUT') {
            throw ErrorFactory.createValidationError('Local storage: tempUrl does not support PUT');
        }
        if (config?.url === undefined || config.url.trim() === '') {
            throw ErrorFactory.createConfigError('Local storage: url is not configured (set STORAGE_URL)');
        }
        const appKey = Env.get('APP_KEY', '');
        if (appKey.trim() === '') {
            throw ErrorFactory.createConfigError('Local storage: APP_KEY is required for signed tempUrl()');
        }
        // Ensure key is safe before embedding in a signed token.
        LocalDriver.resolveKey(config, key);
        const expiresInMs = Math.max(1, options?.expiresIn ?? 60_000);
        const exp = Date.now() + expiresInMs;
        const token = LocalSignedUrl.createToken({ disk: 'local', key, exp, method: 'GET' }, appKey);
        const baseUrl = config.url.replace(/\/$/, '');
        return `${baseUrl}/download?token=${encodeURIComponent(token)}`;
    },
});
export default LocalDriver;
