/**
 * Redis Test Routes
 * Tests Redis connectivity via proxy from Cloudflare Workers
 */
import { Cache } from '../src/cache/Cache.js';
import { Cloudflare } from '../src/config/cloudflare.js';
import { ErrorFactory } from '../src/exceptions/ZintrustError.js';
import { isInt, isNonEmptyString } from '../src/helper/index.js';
import { Mail } from '../src/tools/mail/index.js';
import { WorkerFactory } from '../packages/workers/src/index.js';
import { RedisProxyAdapter } from '../packages/cache-redis/src/index.js';
const ADVANCED_WORKER_SPEC = 'https://wk.zintrust.com/AdvancEmailWorker.js';
const runRedisTest = async (driver, label) => {
    const key = `zt:redis-test:${label}:${Date.now()}`;
    const value = { ok: true, ts: new Date().toISOString() };
    await driver.set(key, value, 30);
    const read = await driver.get(key);
    const exists = await driver.has(key);
    await driver.delete(key);
    const existsAfterDelete = await driver.has(key);
    return {
        key,
        wrote: value,
        read,
        exists,
        existsAfterDelete,
    };
};
const getCacheRouteContext = (req) => {
    const isFlare = Cloudflare?.getWorkersEnv() !== null;
    const storeNameRaw = req.getQueryParam?.('store');
    const storeName = isNonEmptyString(storeNameRaw) ? storeNameRaw.trim() : undefined;
    return {
        storeName,
        runtime: isFlare ? 'Cloudflare Workers' : 'Node',
    };
};
const getCacheStore = (storeName) => storeName === undefined ? Cache : Cache.store(storeName);
const getCacheKeyOrDefault = (req, fallbackPrefix) => {
    const raw = req.getQueryParam?.('key');
    const key = Array.isArray(raw) ? raw[0] : raw;
    if (isNonEmptyString(key))
        return key.trim();
    return `${fallbackPrefix}:${Date.now()}`;
};
const getTtlSeconds = (req) => {
    const raw = req.getQueryParam?.('ttl');
    const value = Array.isArray(raw) ? raw[0] : raw;
    if (!isInt(value, true, { min: 1, max: 60 * 60 }))
        return undefined;
    return Number(value);
};
const getValueForSet = (req) => {
    const raw = req.getQueryParam?.('value');
    const value = Array.isArray(raw) ? raw[0] : raw;
    if (!isNonEmptyString(value)) {
        return { ok: true, ts: new Date().toISOString() };
    }
    const v = value.trim();
    if (v.startsWith('{') || v.startsWith('[')) {
        try {
            return JSON.parse(v);
        }
        catch {
            return v;
        }
    }
    return v;
};
export const testCacheSmoke = async (req, res) => {
    const ctx = getCacheRouteContext(req);
    const key = getCacheKeyOrDefault(req, 'cache-smoke');
    const ttlSeconds = getTtlSeconds(req) ?? 30;
    const value = { ok: true, ts: new Date().toISOString(), key };
    try {
        const store = getCacheStore(ctx.storeName);
        await store.set(key, value, ttlSeconds);
        const read = await store.get(key);
        const exists = await store.has(key);
        await store.delete(key);
        const existsAfterDelete = await store.has(key);
        res.json({
            success: true,
            message: 'Cache smoke test successful',
            runtime: ctx.runtime,
            store: ctx.storeName ?? 'default',
            key,
            ttlSeconds,
            wrote: value,
            read,
            exists,
            existsAfterDelete,
            timestamp: new Date().toISOString(),
        });
    }
    catch (error) {
        res.status(500).json({
            success: false,
            error: 'Cache smoke test failed',
            runtime: ctx.runtime,
            store: ctx.storeName ?? 'default',
            key,
            details: String(error),
            timestamp: new Date().toISOString(),
        });
    }
};
export const testCacheSet = async (req, res) => {
    const ctx = getCacheRouteContext(req);
    const key = getCacheKeyOrDefault(req, 'cache-set');
    const ttlSeconds = getTtlSeconds(req);
    const value = getValueForSet(req);
    try {
        const store = getCacheStore(ctx.storeName);
        await store.set(key, value, ttlSeconds);
        res.json({
            success: true,
            message: 'Cache set successful',
            runtime: ctx.runtime,
            store: ctx.storeName ?? 'default',
            key,
            ttlSeconds: ttlSeconds ?? null,
            timestamp: new Date().toISOString(),
        });
    }
    catch (error) {
        res.status(500).json({
            success: false,
            error: 'Cache set failed',
            runtime: ctx.runtime,
            store: ctx.storeName ?? 'default',
            key,
            details: String(error),
            timestamp: new Date().toISOString(),
        });
    }
};
export const testCacheGet = async (req, res) => {
    const ctx = getCacheRouteContext(req);
    const rawKey = req.getQueryParam?.('key');
    const key = Array.isArray(rawKey) ? rawKey[0] : rawKey;
    if (!isNonEmptyString(key)) {
        res.status(400).json({
            success: false,
            error: 'Missing key',
            message: 'Provide ?key=...',
            runtime: ctx.runtime,
            store: ctx.storeName ?? 'default',
            timestamp: new Date().toISOString(),
        });
        return;
    }
    const trimmedKey = key.trim();
    try {
        const store = getCacheStore(ctx.storeName);
        const value = await store.get(trimmedKey);
        res.json({
            success: true,
            message: 'Cache get successful',
            runtime: ctx.runtime,
            store: ctx.storeName ?? 'default',
            key: trimmedKey,
            value,
            timestamp: new Date().toISOString(),
        });
    }
    catch (error) {
        res.status(500).json({
            success: false,
            error: 'Cache get failed',
            runtime: ctx.runtime,
            store: ctx.storeName ?? 'default',
            key: trimmedKey,
            details: String(error),
            timestamp: new Date().toISOString(),
        });
    }
};
export const testCacheHas = async (req, res) => {
    const ctx = getCacheRouteContext(req);
    const rawKey = req.getQueryParam?.('key');
    const key = Array.isArray(rawKey) ? rawKey[0] : rawKey;
    if (!isNonEmptyString(key)) {
        res.status(400).json({
            success: false,
            error: 'Missing key',
            message: 'Provide ?key=...',
            runtime: ctx.runtime,
            store: ctx.storeName ?? 'default',
            timestamp: new Date().toISOString(),
        });
        return;
    }
    const trimmedKey = key.trim();
    try {
        const store = getCacheStore(ctx.storeName);
        const exists = await store.has(trimmedKey);
        res.json({
            success: true,
            message: 'Cache has successful',
            runtime: ctx.runtime,
            store: ctx.storeName ?? 'default',
            key: trimmedKey,
            exists,
            timestamp: new Date().toISOString(),
        });
    }
    catch (error) {
        res.status(500).json({
            success: false,
            error: 'Cache has failed',
            runtime: ctx.runtime,
            store: ctx.storeName ?? 'default',
            key: trimmedKey,
            details: String(error),
            timestamp: new Date().toISOString(),
        });
    }
};
export const testCacheDelete = async (req, res) => {
    const ctx = getCacheRouteContext(req);
    const rawKey = req.getQueryParam?.('key');
    const key = Array.isArray(rawKey) ? rawKey[0] : rawKey;
    if (!isNonEmptyString(key)) {
        res.status(400).json({
            success: false,
            error: 'Missing key',
            message: 'Provide ?key=...',
            runtime: ctx.runtime,
            store: ctx.storeName ?? 'default',
            timestamp: new Date().toISOString(),
        });
        return;
    }
    const trimmedKey = key.trim();
    try {
        const store = getCacheStore(ctx.storeName);
        await store.delete(trimmedKey);
        const existsAfterDelete = await store.has(trimmedKey);
        res.json({
            success: true,
            message: 'Cache delete successful',
            runtime: ctx.runtime,
            store: ctx.storeName ?? 'default',
            key: trimmedKey,
            existsAfterDelete,
            timestamp: new Date().toISOString(),
        });
    }
    catch (error) {
        res.status(500).json({
            success: false,
            error: 'Cache delete failed',
            runtime: ctx.runtime,
            store: ctx.storeName ?? 'default',
            key: trimmedKey,
            details: String(error),
            timestamp: new Date().toISOString(),
        });
    }
};
export const testCacheClear = async (req, res) => {
    const ctx = getCacheRouteContext(req);
    try {
        const store = getCacheStore(ctx.storeName);
        await store.clear();
        res.json({
            success: true,
            message: 'Cache clear executed',
            note: 'Some drivers (e.g., kv-remote) may not implement clear() and will no-op.',
            runtime: ctx.runtime,
            store: ctx.storeName ?? 'default',
            timestamp: new Date().toISOString(),
        });
    }
    catch (error) {
        res.status(500).json({
            success: false,
            error: 'Cache clear failed',
            runtime: ctx.runtime,
            store: ctx.storeName ?? 'default',
            details: String(error),
            timestamp: new Date().toISOString(),
        });
    }
};
/**
 * Test Redis via HTTP proxy
 */
export const testRedisProxy = async (_req, res) => {
    const isFlare = Cloudflare?.getWorkersEnv() !== null;
    try {
        const driver = RedisProxyAdapter.create();
        const result = await runRedisTest(driver, 'proxy');
        res.json({
            success: true,
            message: 'Redis proxy test successful',
            adapter: 'packages/cache-redis (proxy)',
            runtime: isFlare ? 'Cloudflare Workers' : 'Node',
            data: result,
            timestamp: new Date().toISOString(),
        });
    }
    catch (error) {
        res.status(500).json({
            success: false,
            error: 'Redis proxy test failed',
            details: String(error),
            adapter: 'packages/cache-redis (proxy)',
            runtime: isFlare ? 'Cloudflare Workers' : 'Node',
            timestamp: new Date().toISOString(),
        });
    }
};
/**
 * Test URL-based worker processor resolution (Cloudflare Workers)
 */
export const testWorkerProcessorUrl = async (_req, res) => {
    const isFlare = Cloudflare?.getWorkersEnv() !== null;
    try {
        let resolveProcessorSpec = null;
        try {
            const candidate = WorkerFactory['resolveProcessorSpec'];
            if (typeof candidate === 'function') {
                resolveProcessorSpec = candidate;
            }
        }
        catch {
            resolveProcessorSpec = null;
        }
        if (resolveProcessorSpec === null) {
            throw ErrorFactory.createConfigError('PROCESSOR_SPEC_RESOLVER_UNAVAILABLE');
        }
        const resolved = await resolveProcessorSpec(ADVANCED_WORKER_SPEC);
        if (resolved === undefined || resolved === null) {
            throw ErrorFactory.createConfigError('PROCESSOR_SPEC_NOT_RESOLVED');
        }
        res.json({
            success: true,
            message: 'Processor spec resolved successfully',
            spec: ADVANCED_WORKER_SPEC,
            runtime: isFlare ? 'Cloudflare Workers' : 'Node',
            timestamp: new Date().toISOString(),
        });
    }
    catch (error) {
        res.status(500).json({
            success: false,
            error: 'Processor spec resolution failed',
            spec: ADVANCED_WORKER_SPEC,
            details: String(error),
            runtime: isFlare ? 'Cloudflare Workers' : 'Node',
            timestamp: new Date().toISOString(),
        });
    }
};
const getMailConfig = () => {
    const mailHost = process.env['MAIL_HOST'] ?? '';
    const mailUsername = process.env['MAIL_USERNAME'] ?? '';
    const mailPassword = process.env['MAIL_PASSWORD'] ?? '';
    const mailDriver = process.env['MAIL_DRIVER'] ?? process.env['MAIL_CONNECTION'] ?? 'smtp';
    return {
        mailHost,
        mailUsername,
        mailPassword,
        mailDriver,
        isConfigured: Boolean(mailHost) && Boolean(mailUsername) && Boolean(mailPassword),
        configStatus: {
            driver: mailDriver,
            host: mailHost ? 'configured' : 'missing',
            username: mailUsername ? 'configured' : 'missing',
            password: mailPassword ? 'configured' : 'missing',
        },
    };
};
const getMailErrorDetails = (errorMessage) => {
    const isProxyAuthError = errorMessage.includes('SMTP proxy forbidden') ||
        errorMessage.includes('SMTP proxy unauthorized') ||
        errorMessage.includes('ForbiddenError');
    const isConnectionError = errorMessage.includes('ConnectionError') ||
        errorMessage.includes('ECONNREFUSED') ||
        errorMessage.includes('ETIMEDOUT');
    const isAuthError = errorMessage.includes('auth') || errorMessage.includes('535') || errorMessage.includes('530');
    const isConfigError = errorMessage.includes('Configuration') || errorMessage.includes('config');
    if (isProxyAuthError) {
        return {
            errorType: 'proxy-auth',
            suggestion: 'Ensure SMTP proxy signing credentials match between worker and proxy (SMTP_PROXY_KEY_ID/SMTP_PROXY_SECRET or APP_KEY).',
        };
    }
    if (isConnectionError) {
        return {
            errorType: 'connection',
            suggestion: 'Check MAIL_HOST, MAIL_PORT, and network connectivity',
        };
    }
    if (isAuthError) {
        return {
            errorType: 'authentication',
            suggestion: 'Verify MAIL_USERNAME and MAIL_PASSWORD are correct',
        };
    }
    if (isConfigError) {
        return {
            errorType: 'configuration',
            suggestion: 'Check mail driver configuration',
        };
    }
    return {
        errorType: 'unknown',
        suggestion: 'Check mail service logs for more details',
    };
};
const handleMailConfiguration = (mailConfig, isFlare, res) => {
    if (mailConfig.mailDriver === 'smtp' && !mailConfig.isConfigured) {
        res.status(400).json({
            success: false,
            error: 'Mail configuration incomplete',
            message: 'SMTP mail driver requires MAIL_HOST, MAIL_USERNAME, and MAIL_PASSWORD environment variables',
            config: mailConfig.configStatus,
            runtime: isFlare ? 'Cloudflare Workers' : 'Node',
            timestamp: new Date().toISOString(),
        });
        return false;
    }
    return true;
};
/**
 * Test sending email using configured mail driver
 */
export const testMailSend = async (req, res) => {
    const isFlare = Cloudflare?.getWorkersEnv() !== null;
    const mailConfig = getMailConfig();
    if (!handleMailConfiguration(mailConfig, isFlare, res))
        return;
    try {
        const to = req.getQueryParam?.('to') ?? 'test@zintrust.com';
        const subject = 'SMTP test from ZinTrust';
        const htmlContent = await Mail.render({
            template: 'welcome',
            variables: { alertType: 'critical' },
        });
        const result = await Mail.send({
            to: to ?? 'test@zintrust.com',
            subject: subject ?? 'Worker Notification from ZinTrust',
            text: `Worker job completed successfully.`,
            html: htmlContent,
            from: {
                address: 'no-reply@engage.vizo.app',
                name: 'ZinTrust Advanced Worker',
            },
        });
        res.json({
            success: true,
            message: 'Mail send test completed successfully',
            to,
            result,
            config: mailConfig.configStatus,
            runtime: isFlare ? 'Cloudflare Workers' : 'Node',
            timestamp: new Date().toISOString(),
        });
    }
    catch (error) {
        const errorMessage = String(error);
        const errorDetails = typeof error === 'object' && error !== null && 'details' in error
            ? error.details
            : undefined;
        const { errorType, suggestion } = getMailErrorDetails(errorMessage);
        res.status(500).json({
            success: false,
            error: 'Mail send test failed',
            errorType,
            details: errorDetails ?? errorMessage,
            suggestion,
            config: mailConfig.configStatus,
            runtime: isFlare ? 'Cloudflare Workers' : 'Node',
            timestamp: new Date().toISOString(),
        });
    }
};
