import { BaseCommand } from '../BaseCommand.js';
import { resolveNpmPath } from '../../common/index.js';
import { appConfig } from '../../config/app.js';
import { ErrorFactory } from '../../exceptions/ZintrustError.js';
import { execFileSync } from '../../node-singletons/child-process.js';
import { existsSync, readFileSync } from '../../node-singletons/fs.js';
import * as path from '../../node-singletons/path.js';
import { EnvFile } from '../../toolkit/Secrets/EnvFile.js';
const toStringArray = (value) => {
    if (typeof value === 'string')
        return [value];
    if (!Array.isArray(value))
        return [];
    return value.filter((v) => typeof v === 'string');
};
const uniq = (items) => {
    const seen = new Set();
    const out = [];
    for (const item of items) {
        const normalized = item.trim();
        if (normalized === '' || seen.has(normalized))
            continue;
        seen.add(normalized);
        out.push(normalized);
    }
    return out;
};
const readZintrustConfig = (cwd) => {
    const filePath = path.join(cwd, '.zintrust.json');
    if (!existsSync(filePath)) {
        return {};
    }
    try {
        const raw = readFileSync(filePath, 'utf8');
        const parsed = JSON.parse(raw);
        return typeof parsed === 'object' && parsed !== null ? parsed : {};
    }
    catch (error) {
        throw ErrorFactory.createCliError('Failed to parse .zintrust.json', error);
    }
};
const getConfigArray = (config, key) => {
    const raw = config[key];
    if (!Array.isArray(raw))
        return [];
    return uniq(raw.filter((item) => typeof item === 'string'));
};
const resolveConfigGroups = (options) => {
    return uniq(toStringArray(options.var));
};
const resolveWranglerEnvs = (options) => {
    const requested = uniq(toStringArray(options.wg));
    if (requested.length === 0)
        return ['worker'];
    return requested;
};
const parseEnvPath = (options) => {
    const direct = options['env_path'];
    if (typeof direct === 'string' && direct.trim() !== '')
        return direct;
    return '.env';
};
const resolveValue = (key, envMap) => {
    const fromFile = envMap[key];
    const fromProcess = process.env[key];
    return fromFile ?? fromProcess ?? '';
};
const getPutTimeoutMs = () => {
    const raw = process.env['ZT_PUT_TIMEOUT_MS'];
    if (typeof raw !== 'string')
        return 120000;
    const parsed = Number.parseInt(raw, 10);
    if (!Number.isFinite(parsed) || parsed <= 0)
        return 120000;
    return parsed;
};
const putSecret = (wranglerEnv, key, value, configPath) => {
    const npmPath = resolveNpmPath();
    const args = ['exec', '--yes', '--', 'wrangler'];
    if (typeof configPath === 'string' && configPath.trim().length > 0) {
        args.push('--config', configPath.trim());
    }
    args.push('secret', 'put', key, '--env', wranglerEnv);
    execFileSync(npmPath, args, {
        stdio: ['pipe', 'inherit', 'inherit'],
        input: value,
        encoding: 'utf8',
        timeout: getPutTimeoutMs(),
        killSignal: 'SIGTERM',
        env: appConfig.getSafeEnv(),
    });
};
const addOptions = (command) => {
    command
        .argument('[provider]', 'Secret provider (cloudflare)', 'cloudflare')
        .option('--wg <env...>', 'Wrangler environment target(s), e.g. d1-proxy kv-proxy')
        .option('--var <configKey...>', 'Config array key(s) from .zintrust.json (e.g. d1_env kv_env)')
        .option('--env_path <path>', 'Path to env file used as source values', '.env')
        .option('-c, --config <path>', 'Wrangler config file to target (optional)')
        .option('--dry-run', 'Show what would be uploaded without calling wrangler');
};
const ensureCloudflareProvider = (providerRaw) => {
    if (providerRaw.toLowerCase() === 'cloudflare')
        return;
    throw ErrorFactory.createCliError('Only cloudflare provider is supported for `zin put`');
};
const resolveSelectedKeys = (cmd, config, options) => {
    const configGroups = resolveConfigGroups(options);
    if (configGroups.length === 0) {
        throw ErrorFactory.createCliError('No config groups selected. Use --var <group>.');
    }
    const selectedKeys = uniq(configGroups.flatMap((groupKey) => {
        const keys = getConfigArray(config, groupKey);
        if (keys.length === 0) {
            cmd.warn(`Group \`${groupKey}\` is missing or empty in .zintrust.json`);
        }
        return keys;
    }));
    if (selectedKeys.length === 0) {
        throw ErrorFactory.createCliError('No secret keys resolved from selected groups.');
    }
    return selectedKeys;
};
const getFailureReason = (error) => error instanceof Error ? error.message : String(error);
const reportResult = (cmd, pushed, failures) => {
    cmd.success(`Cloudflare secrets report: pushed=${pushed}, failed=${failures.length}`);
    for (const item of failures) {
        cmd.warn(`${item.key} -> ${item.wranglerEnv}: ${item.reason}`);
    }
};
const processPut = (cmd, wranglerEnvs, selectedKeys, envMap, dryRun, configPath) => {
    let pushed = 0;
    const failures = [];
    for (const wranglerEnv of wranglerEnvs) {
        for (const key of selectedKeys) {
            const value = resolveValue(key, envMap);
            if (value.trim() === '') {
                failures.push({ wranglerEnv, key, reason: 'empty value' });
                continue;
            }
            try {
                if (!dryRun) {
                    cmd.info(`putting ${key} -> ${wranglerEnv}...`);
                    putSecret(wranglerEnv, key, value, configPath);
                }
                pushed += 1;
                cmd.info(`${dryRun ? '[dry-run] ' : ''}put ${key} -> ${wranglerEnv}`);
            }
            catch (error) {
                failures.push({ wranglerEnv, key, reason: getFailureReason(error) });
            }
        }
    }
    return { pushed, failures };
};
const execute = async (cmd, options) => {
    ensureCloudflareProvider(String(options.args?.[0] ?? 'cloudflare'));
    const cwd = process.cwd();
    const config = readZintrustConfig(cwd);
    const selectedKeys = resolveSelectedKeys(cmd, config, options);
    const envFilePath = parseEnvPath(options);
    const envMap = await EnvFile.read({ cwd, path: envFilePath });
    const wranglerEnvs = resolveWranglerEnvs(options);
    const dryRun = options.dryRun === true;
    const configPath = typeof options.config === 'string' ? options.config.trim() : '';
    if (configPath !== '' && !existsSync(path.join(cwd, configPath))) {
        throw ErrorFactory.createCliError(`Wrangler config not found: ${configPath}`);
    }
    const result = processPut(cmd, wranglerEnvs, selectedKeys, envMap, dryRun, configPath === '' ? undefined : configPath);
    reportResult(cmd, result.pushed, result.failures);
};
export const PutCommand = Object.freeze({
    create() {
        const cmd = BaseCommand.create({
            name: 'put',
            description: 'Put secrets to Cloudflare with dynamic groups from .zintrust.json',
            addOptions,
            execute: async (options) => execute(cmd, options),
        });
        return cmd;
    },
});
export default PutCommand;
