import { join } from 'node:path';
import { CapabilityAwareStructuredCaller } from '../../../agents/structured-caller.js';
import { buildRunPaths } from '../../../core/workflow/run/run-paths.js';
import { resolveRuntimeConfig } from '../../../core/runtime/runtime-environment.js';
import { loadPersonaSessions, loadWorktreeSessions, resolveWorkflowConfigValues, updatePersonaSession, updateWorktreeSession, } from '../../../infra/config/index.js';
import { resolveConfigValueWithSource, } from '../../../infra/config/resolveConfigValue.js';
import { getGlobalConfigDir } from '../../../infra/config/paths.js';
import { createSessionLog, generateSessionId, initNdjsonLog } from '../../../infra/fs/index.js';
import { isQuietMode } from '../../../shared/context.js';
import { TaskPrefixWriter } from '../../../shared/ui/TaskPrefixWriter.js';
import { createLogger, generateReportDir, getDebugPromptsLogFile, isValidReportDirName, preventSleep } from '../../../shared/utils/index.js';
import { createProviderEventLogger, isProviderEventsEnabled } from '../../../shared/utils/providerEventLogger.js';
import { sanitizeTerminalText } from '../../../shared/utils/text.js';
import { createUsageEventLogger, isUsageEventsEnabled } from '../../../shared/utils/usageEventLogger.js';
import { initializeOtelFoundation } from '../../../infra/observability/otelFoundation.js';
import { initAnalyticsWriter } from '../../analytics/index.js';
import { AnalyticsEmitter } from './analyticsEmitter.js';
import { createOutputFns, createPrefixedStreamHandler } from './outputFns.js';
import { RunMetaManager } from './runMeta.js';
import { SessionLogger } from './sessionLogger.js';
import { createTraceReportWriter } from './traceReportWriter.js';
import { sanitizeTextForStorage } from './traceReportRedaction.js';
import { assertTaskPrefixPair, detectStepType } from './workflowExecutionUtils.js';
const log = createLogger('workflow');
export async function createWorkflowExecutionBootstrap(workflowConfig, task, cwd, options) {
    const { headerPrefix = 'Running Workflow:', interactiveUserInput = false } = options;
    const projectCwd = options.projectCwd;
    const safeWorkflowName = sanitizeTerminalText(workflowConfig.name);
    assertTaskPrefixPair(options.taskPrefix, options.taskColorIndex);
    const prefixWriter = options.taskPrefix != null
        ? new TaskPrefixWriter({
            taskName: options.taskPrefix,
            colorIndex: options.taskColorIndex,
            displayLabel: options.taskDisplayLabel,
        })
        : undefined;
    const out = createOutputFns(prefixWriter);
    out.header(`${headerPrefix} ${safeWorkflowName}`);
    const displayRef = { current: null };
    const handlerRef = { current: null };
    const streamHandler = prefixWriter
        ? createPrefixedStreamHandler(prefixWriter)
        : (event) => {
            if (!displayRef.current || event.type === 'result') {
                return;
            }
            if (!handlerRef.current) {
                handlerRef.current = displayRef.current.createHandler();
            }
            handlerRef.current(event);
        };
    const isRetry = Boolean(options.startStep || options.retryNote || options.resumePoint);
    const isWorktree = cwd !== projectCwd;
    log.debug('Session mode', { isRetry, isWorktree });
    const runSlug = options.reportDirName ?? generateReportDir(task);
    if (!isValidReportDirName(runSlug)) {
        throw new Error(`Invalid reportDirName: ${runSlug}`);
    }
    const runPaths = buildRunPaths(cwd, runSlug);
    const runMetaManager = new RunMetaManager(runPaths, task, workflowConfig.name, options.directResume);
    const sessionLog = createSessionLog(task, projectCwd, workflowConfig.name);
    const globalConfig = resolveWorkflowConfigValues(projectCwd, [
        'notificationSound',
        'notificationSoundEvents',
        'provider',
        'rateLimitFallback',
        'runtime',
        'preventSleep',
        'model',
        'logging',
        'analytics',
        'observability',
    ]);
    const traceReportMode = globalConfig.logging?.trace === true ? 'full' : 'redacted';
    const allowSensitiveData = traceReportMode === 'full';
    const workflowSessionId = generateSessionId();
    const ndjsonLogPath = initNdjsonLog(workflowSessionId, sanitizeTextForStorage(task, allowSensitiveData), workflowConfig.name, { logsDir: runPaths.logsAbs });
    const sessionLogger = new SessionLogger(ndjsonLogPath, allowSensitiveData);
    if (options.interactiveMetadata) {
        sessionLogger.writeInteractiveMetadata(options.interactiveMetadata);
    }
    const shouldNotify = globalConfig.notificationSound !== false;
    const shouldNotifyIterationLimit = shouldNotify && globalConfig.notificationSoundEvents?.iterationLimit !== false;
    const shouldNotifyWorkflowComplete = shouldNotify && globalConfig.notificationSoundEvents?.workflowComplete !== false;
    const shouldNotifyWorkflowAbort = shouldNotify && globalConfig.notificationSoundEvents?.workflowAbort !== false;
    const currentProvider = options.provider ?? globalConfig.provider;
    if (!currentProvider) {
        throw new Error('No provider configured. Set "provider" in ~/.takt/config.yaml');
    }
    const currentProviderSource = resolveProviderFieldSource(projectCwd, 'provider', options.provider, options.providerSource);
    const configuredModel = options.model ?? globalConfig.model;
    const configuredModelSource = resolveProviderFieldSource(projectCwd, 'model', options.model, options.modelSource);
    const effectiveWorkflowConfig = {
        ...workflowConfig,
        rateLimitFallback: workflowConfig.rateLimitFallback ?? globalConfig.rateLimitFallback,
        runtime: resolveRuntimeConfig(globalConfig.runtime, workflowConfig.runtime),
        ...(options.maxStepsOverride !== undefined ? { maxSteps: options.maxStepsOverride } : {}),
    };
    const providerEventLogger = createProviderEventLogger({
        logsDir: runPaths.logsAbs,
        sessionId: workflowSessionId,
        runId: runSlug,
        provider: currentProvider,
        step: options.startStep ?? workflowConfig.initialStep,
        enabled: isProviderEventsEnabled(globalConfig),
    });
    const usageEventLogger = createUsageEventLogger({
        logsDir: runPaths.logsAbs,
        sessionId: workflowSessionId,
        runId: runSlug,
        provider: currentProvider,
        providerModel: configuredModel ?? '(default)',
        step: options.startStep ?? workflowConfig.initialStep,
        stepType: 'normal',
        enabled: isUsageEventsEnabled(globalConfig),
    });
    initAnalyticsWriter(globalConfig.analytics?.enabled === true, globalConfig.analytics?.eventsPath ?? join(getGlobalConfigDir(), 'analytics', 'events'));
    if (globalConfig.preventSleep) {
        preventSleep();
    }
    const analyticsEmitter = new AnalyticsEmitter(runSlug, currentProvider, configuredModel ?? '(default)');
    const structuredCaller = new CapabilityAwareStructuredCaller();
    const savedSessions = isRetry
        ? (isWorktree
            ? loadWorktreeSessions(projectCwd, cwd, currentProvider)
            : loadPersonaSessions(projectCwd, currentProvider))
        : {};
    const sessionUpdateHandler = isWorktree
        ? (personaName, personaSessionId) => updateWorktreeSession(projectCwd, cwd, personaName, personaSessionId, currentProvider)
        : (persona, personaSessionId) => updatePersonaSession(projectCwd, persona, personaSessionId, currentProvider);
    const writeTraceReportOnce = createTraceReportWriter({
        sessionLogger,
        ndjsonLogPath,
        tracePath: join(runPaths.runRootAbs, 'trace.md'),
        workflowName: workflowConfig.name,
        task,
        runSlug,
        promptLogPath: getDebugPromptsLogFile() ?? undefined,
        mode: traceReportMode,
        logger: log,
    });
    const observabilityOptions = globalConfig.observability.enabled
        && (globalConfig.observability.sessionLogExporter || globalConfig.observability.monitor)
        ? {
            ...(globalConfig.observability.sessionLogExporter
                ? {
                    sessionLogExporter: {
                        runId: runSlug,
                        shadowLogPath: join(runPaths.logsAbs, `${workflowSessionId}-otel-session-shadow.jsonl`),
                        sanitizedTask: sanitizeTextForStorage(task, allowSensitiveData),
                        workflowName: workflowConfig.name,
                    },
                }
                : {}),
            ...(globalConfig.observability.monitor
                ? { monitorJsonExporter: { runId: runSlug, monitorPath: join(runPaths.runRootAbs, 'monitor.json') } }
                : {}),
        }
        : undefined;
    const observabilityHandle = await initializeOtelFoundation(globalConfig.observability, observabilityOptions);
    return {
        interactiveUserInput,
        prefixWriter,
        out,
        displayRef,
        handlerRef,
        streamHandler,
        isRetry,
        isWorktree,
        runSlug,
        runPaths,
        runMetaManager,
        sessionLog,
        ndjsonLogPath,
        sessionLogger,
        sanitizeObservabilityText: (text) => sanitizeTextForStorage(text, allowSensitiveData),
        shouldNotifyIterationLimit,
        shouldNotifyWorkflowComplete,
        shouldNotifyWorkflowAbort,
        currentProvider,
        currentProviderSource,
        configuredModel,
        configuredModelSource,
        effectiveWorkflowConfig,
        providerEventLogger,
        usageEventLogger,
        observability: globalConfig.observability,
        observabilityHandle,
        analyticsEmitter,
        structuredCaller,
        savedSessions,
        sessionUpdateHandler,
        writeTraceReportOnce,
    };
}
function mapConfigSourceToResolutionSource(source) {
    switch (source) {
        case 'project':
            return 'project';
        case 'global':
            return 'global';
        case 'default':
            return 'default';
        default:
            // 'env' / 'workflow' do not occur for provider/model in bootstrap context.
            return 'default';
    }
}
function resolveProviderFieldSource(projectCwd, key, cliValue, cliSource) {
    if (cliValue !== undefined) {
        return cliSource ?? 'cli';
    }
    try {
        const resolved = resolveConfigValueWithSource(projectCwd, key);
        if (resolved.value !== undefined) {
            return mapConfigSourceToResolutionSource(resolved.source);
        }
    }
    catch {
        // Config resolution may fail in test contexts where paths are synthetic;
        // fall back to 'global' as a reasonable default since the value itself
        // was loaded successfully via resolveWorkflowConfigValues.
    }
    return 'global';
}
export { detectStepType, isQuietMode };
//# sourceMappingURL=workflowExecutionBootstrap.js.map