import { writeFileSync } from 'node:fs';
import { stringify as stringifyYaml } from 'yaml';
import { GlobalConfigSchema } from '../../../core/models/index.js';
import { normalizeConfigProviderReference, } from '../providerReference.js';
import { normalizeProviderProfiles, normalizeWorkflowOverrides, normalizePipelineConfig, normalizePersonaProviders, normalizeTaktProviders, buildRawTaktProvidersOrThrow, normalizeRuntime, normalizeRateLimitFallback, } from '../configNormalizers.js';
import { resolveAliasedPreviewCount, } from '../configKeyAliases.js';
import { normalizeObservabilityConfig } from '../observabilityConfig.js';
import { getGlobalConfigPath } from '../paths.js';
import { invalidateAllResolvedConfigCache } from '../resolutionCache.js';
import { validateProviderModelCompatibility } from '../providerModelCompatibility.js';
import { expandOptionalHomePath } from '../pathExpansion.js';
import { sanitizeConfigValue } from './globalConfigLegacyMigration.js';
import { serializeGlobalConfig } from './globalConfigSerializer.js';
import { loadGlobalConfigTrace } from '../traced/tracedConfigLoader.js';
export { validateCliPath } from './cliPathValidator.js';
function getRecord(value) {
    if (typeof value !== 'object' || value === null || Array.isArray(value)) {
        return undefined;
    }
    return value;
}
function assertNoUnknownGlobalConfigKeys(rawConfig) {
    const parsedResult = GlobalConfigSchema.safeParse(rawConfig);
    if (parsedResult.success) {
        return;
    }
    const issue = parsedResult.error.issues.find((candidate) => candidate.code === 'unrecognized_keys');
    if (!issue) {
        return;
    }
    throw new Error(issue.message);
}
function assertValidGlobalConfig(rawConfig, configPath, onlyUnrecognizedKeys = false) {
    const parsedResult = GlobalConfigSchema.safeParse(rawConfig);
    if (!parsedResult.success) {
        const firstIssue = onlyUnrecognizedKeys
            ? parsedResult.error.issues.find((issue) => issue.code === 'unrecognized_keys')
            : parsedResult.error.issues[0];
        if (!firstIssue) {
            return;
        }
        throw new Error(`Configuration error: invalid ${firstIssue.path.join('.')} in ${configPath}: ${firstIssue.message ?? 'Invalid configuration value'}`);
    }
}
export class GlobalConfigManager {
    static instance = null;
    cachedConfig = null;
    cachedTrace = null;
    constructor() { }
    static getInstance() {
        if (!GlobalConfigManager.instance) {
            GlobalConfigManager.instance = new GlobalConfigManager();
        }
        return GlobalConfigManager.instance;
    }
    static resetInstance() {
        GlobalConfigManager.instance = null;
    }
    invalidateCache() {
        this.cachedConfig = null;
        this.cachedTrace = null;
    }
    load() {
        if (this.cachedConfig !== null) {
            return this.cachedConfig;
        }
        const configPath = getGlobalConfigPath();
        const { parsedConfig, rawConfig, trace } = loadGlobalConfigTrace(configPath, (value) => {
            if (value == null) {
                return value;
            }
            const sanitized = getRecord(sanitizeConfigValue(value, 'config'));
            if (!sanitized) {
                throw new Error('Configuration error: ~/.takt/config.yaml must be a YAML object.');
            }
            return sanitized;
        });
        assertValidGlobalConfig(parsedConfig, configPath, true);
        assertNoUnknownGlobalConfigKeys(rawConfig);
        const parsed = GlobalConfigSchema.parse(rawConfig);
        const normalizedProvider = normalizeConfigProviderReference(parsed.provider, parsed.model, parsed.provider_options);
        const config = {
            language: parsed.language,
            provider: normalizedProvider.provider,
            model: normalizedProvider.model,
            logging: parsed.logging ? {
                level: parsed.logging.level,
                trace: parsed.logging.trace,
                debug: parsed.logging.debug,
                providerEvents: parsed.logging.provider_events,
                usageEvents: parsed.logging.usage_events,
            } : undefined,
            analytics: parsed.analytics ? {
                enabled: parsed.analytics.enabled,
                eventsPath: expandOptionalHomePath(parsed.analytics.events_path),
                retentionDays: parsed.analytics.retention_days,
            } : undefined,
            observability: normalizeObservabilityConfig(parsed.observability),
            worktreeDir: expandOptionalHomePath(parsed.worktree_dir),
            allowGitHooks: parsed.allow_git_hooks,
            allowGitFilters: parsed.allow_git_filters,
            vcsProvider: parsed.vcs_provider,
            autoPr: parsed.auto_pr,
            draftPr: parsed.draft_pr,
            disabledBuiltins: parsed.disabled_builtins,
            enableBuiltinWorkflows: parsed.enable_builtin_workflows,
            anthropicApiKey: parsed.anthropic_api_key,
            openaiApiKey: parsed.openai_api_key,
            geminiApiKey: parsed.gemini_api_key,
            googleApiKey: parsed.google_api_key,
            groqApiKey: parsed.groq_api_key,
            openrouterApiKey: parsed.openrouter_api_key,
            codexCliPath: expandOptionalHomePath(parsed.codex_cli_path),
            claudeCliPath: expandOptionalHomePath(parsed.claude_cli_path),
            cursorCliPath: expandOptionalHomePath(parsed.cursor_cli_path),
            copilotCliPath: expandOptionalHomePath(parsed.copilot_cli_path),
            kiroCliPath: expandOptionalHomePath(parsed.kiro_cli_path),
            copilotGithubToken: parsed.copilot_github_token,
            kiroApiKey: parsed.kiro_api_key,
            opencodeApiKey: parsed.opencode_api_key,
            cursorApiKey: parsed.cursor_api_key,
            bookmarksFile: expandOptionalHomePath(parsed.bookmarks_file),
            workflowCategoriesFile: expandOptionalHomePath(parsed.workflow_categories_file),
            providerOptions: normalizedProvider.providerOptions,
            rateLimitFallback: normalizeRateLimitFallback(parsed.rate_limit_fallback),
            providerProfiles: normalizeProviderProfiles(parsed.provider_profiles),
            runtime: normalizeRuntime(parsed.runtime),
            workflowRuntimePrepare: parsed.workflow_runtime_prepare ? {
                customScripts: parsed.workflow_runtime_prepare.custom_scripts,
            } : undefined,
            workflowCommandGates: parsed.workflow_command_gates ? {
                customScripts: parsed.workflow_command_gates.custom_scripts,
            } : undefined,
            workflowArpeggio: parsed.workflow_arpeggio ? {
                customDataSourceModules: parsed.workflow_arpeggio.custom_data_source_modules,
                customMergeInlineJs: parsed.workflow_arpeggio.custom_merge_inline_js,
                customMergeFiles: parsed.workflow_arpeggio.custom_merge_files,
            } : undefined,
            syncConflictResolver: parsed.sync_conflict_resolver ? {
                autoApproveTools: parsed.sync_conflict_resolver.auto_approve_tools,
            } : undefined,
            workflowMcpServers: parsed.workflow_mcp_servers ? {
                stdio: parsed.workflow_mcp_servers.stdio,
                sse: parsed.workflow_mcp_servers.sse,
                http: parsed.workflow_mcp_servers.http,
            } : undefined,
            preventSleep: parsed.prevent_sleep,
            notificationSound: parsed.notification_sound,
            notificationSoundEvents: parsed.notification_sound_events ? {
                iterationLimit: parsed.notification_sound_events.iteration_limit,
                workflowComplete: parsed.notification_sound_events.workflow_complete,
                workflowAbort: parsed.notification_sound_events.workflow_abort,
                runComplete: parsed.notification_sound_events.run_complete,
                runAbort: parsed.notification_sound_events.run_abort,
            } : undefined,
            autoFetch: parsed.auto_fetch,
            baseBranch: parsed.base_branch,
            workflowOverrides: normalizeWorkflowOverrides(parsed.workflow_overrides),
            // Project-local keys (also accepted in global config)
            pipeline: normalizePipelineConfig(parsed.pipeline),
            taktProviders: normalizeTaktProviders(parsed.takt_providers),
            personaProviders: normalizePersonaProviders(parsed.persona_providers),
            branchNameStrategy: parsed.branch_name_strategy,
            minimalOutput: parsed.minimal_output,
            concurrency: parsed.concurrency,
            taskPollIntervalMs: parsed.task_poll_interval_ms,
            interactivePreviewSteps: resolveAliasedPreviewCount(parsed),
            syncProjectLocalTaktOnRetry: parsed.sync_project_local_takt_on_retry,
        };
        validateProviderModelCompatibility(config.provider, config.model);
        this.cachedConfig = config;
        this.cachedTrace = trace;
        return config;
    }
    getTrace() {
        if (this.cachedTrace !== null) {
            return this.cachedTrace;
        }
        this.load();
        if (this.cachedTrace === null) {
            throw new Error('Global config trace is not available');
        }
        return this.cachedTrace;
    }
    save(config) {
        const configPath = getGlobalConfigPath();
        const raw = serializeGlobalConfig(config);
        const rawTaktProviders = buildRawTaktProvidersOrThrow(config.taktProviders);
        if (rawTaktProviders) {
            raw.takt_providers = rawTaktProviders;
        }
        writeFileSync(configPath, stringifyYaml(raw), 'utf-8');
        this.invalidateCache();
        invalidateAllResolvedConfigCache();
    }
}
export function invalidateGlobalConfigCache() {
    GlobalConfigManager.getInstance().invalidateCache();
    invalidateAllResolvedConfigCache();
}
export function loadGlobalConfig() {
    return GlobalConfigManager.getInstance().load();
}
export function saveGlobalConfig(config) {
    GlobalConfigManager.getInstance().save(config);
}
export function loadGlobalConfigTraceState() {
    return GlobalConfigManager.getInstance().getTrace();
}
//# sourceMappingURL=globalConfigCore.js.map