import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
import { spawnSync } from 'node:child_process';
import { existsSync, mkdirSync, readFileSync, unlinkSync, writeFileSync, } from 'node:fs';
import { dirname, join } from 'node:path';
import { Box, Text, useFocus, useInput } from 'ink';
import SelectInput from 'ink-select-input';
import Spinner from 'ink-spinner';
import { useEffect, useState } from 'react';
import { TitledBoxWithPreferences } from '../components/ui/titled-box.js';
import { getColors } from '../config/index.js';
import { getConfigPath } from '../config/paths.js';
import { useResponsiveTerminal } from '../hooks/useTerminalWidth.js';
import { formatError } from '../utils/error-formatter.js';
import { logError, logInfo } from '../utils/message-queue.js';
import { LocationStep } from './steps/location-step.js';
function detectEditor() {
    return (process.env.EDITOR ||
        process.env.VISUAL ||
        (process.platform === 'win32' ? 'notepad' : 'nano'));
}
export function BaseConfigWizard({ title, focusId, configFileName, initialItems, parseConfig, buildConfig, hasItems, renderConfigureStep, renderSummaryItems, renderCompleteExtras, projectDir, onComplete, onCancel, }) {
    const colors = getColors();
    const [step, setStep] = useState('location');
    const [configPath, setConfigPath] = useState('');
    const [items, setItems] = useState(initialItems);
    const [error, setError] = useState(null);
    const [configCorrupted, setConfigCorrupted] = useState(false);
    const { boxWidth, isNarrow } = useResponsiveTerminal();
    useFocus({ autoFocus: true, id: focusId });
    useEffect(() => {
        if (!configPath)
            return;
        void Promise.resolve().then(() => {
            try {
                if (existsSync(configPath)) {
                    try {
                        const content = readFileSync(configPath, 'utf-8');
                        const raw = JSON.parse(content);
                        setItems(parseConfig(raw));
                        setConfigCorrupted(false);
                    }
                    catch (err) {
                        logError('Failed to load configuration', true, {
                            context: { configPath },
                            error: formatError(err),
                        });
                        setConfigCorrupted(true);
                        setError(`Configuration file has invalid JSON and cannot be loaded. ` +
                            `Fix the syntax error or delete the file before proceeding. ` +
                            `File: ${configPath}`);
                    }
                }
            }
            catch (err) {
                logError('Failed to load existing configuration', true, {
                    context: { configPath },
                    error: formatError(err),
                });
            }
        });
    }, [configPath, parseConfig]);
    const writeConfigToDisk = (data) => {
        if (!hasItems(data))
            return;
        if (configCorrupted) {
            throw new Error('Cannot save: the existing configuration file contains invalid JSON. ' +
                'Fix the syntax error or delete the file before saving.');
        }
        const config = buildConfig(data);
        const configDir = dirname(configPath);
        if (!existsSync(configDir)) {
            mkdirSync(configDir, { recursive: true });
        }
        writeFileSync(configPath, JSON.stringify(config, null, 2), 'utf-8');
    };
    const handleLocationComplete = (location) => {
        const baseDir = location === 'project' ? projectDir : getConfigPath();
        setConfigPath(join(baseDir, configFileName));
        setStep('configure');
    };
    const handleConfigureComplete = (newItems) => {
        setItems(newItems);
        setStep('summary');
    };
    const handleSave = () => {
        setStep('saving');
        setError(null);
        try {
            writeConfigToDisk(items);
            setStep('complete');
        }
        catch (err) {
            setError(err instanceof Error ? err.message : 'Failed to save configuration');
            setStep('summary');
        }
    };
    const handleDeleteConfig = () => setStep('confirm-delete');
    const handleConfirmDelete = () => {
        try {
            if (existsSync(configPath)) {
                unlinkSync(configPath);
                logInfo(`Deleted configuration file: ${configPath}`);
            }
            setConfigCorrupted(false);
            setError(null);
            onComplete(configPath);
        }
        catch (err) {
            setError(err instanceof Error ? err.message : 'Failed to delete configuration');
            setStep('configure');
        }
    };
    const openInEditor = () => {
        try {
            // Skip writing when config is corrupted — open the existing
            if (!configCorrupted) {
                writeConfigToDisk(items);
            }
            const editor = detectEditor();
            process.stdout.write('\x1B[?25h');
            process.stdin.setRawMode?.(false);
            const result = spawnSync(editor, [configPath], { stdio: 'inherit' });
            process.stdin.setRawMode?.(true);
            process.stdout.write('\x1B[?25l');
            if (result.status === 0) {
                if (existsSync(configPath)) {
                    try {
                        const editedContent = readFileSync(configPath, 'utf-8');
                        const editedRaw = JSON.parse(editedContent);
                        setItems(parseConfig(editedRaw));
                        setConfigCorrupted(false);
                    }
                    catch (parseErr) {
                        setError(parseErr instanceof Error
                            ? `Invalid JSON: ${parseErr.message}`
                            : 'Failed to parse edited configuration');
                        setStep('summary');
                        return;
                    }
                }
                setStep('summary');
                setError(null);
            }
            else {
                setError('Editor exited with an error. Changes may not be saved.');
                setStep('summary');
            }
        }
        catch (err) {
            process.stdin.setRawMode?.(true);
            process.stdout.write('\x1B[?25l');
            setError(err instanceof Error
                ? `Failed to open editor: ${err.message}`
                : 'Failed to open editor');
            setStep('summary');
        }
    };
    useInput((input, key) => {
        if (step === 'complete' && key.return) {
            onComplete(configPath);
            return;
        }
        if (key.escape) {
            onCancel?.();
            return;
        }
        if (key.ctrl &&
            input === 'e' &&
            configPath &&
            (step === 'configure' || step === 'summary')) {
            openInEditor();
        }
    });
    const renderStep = () => {
        switch (step) {
            case 'location': {
                return (_jsx(LocationStep, { projectDir: projectDir, onComplete: handleLocationComplete, onBack: onCancel, configFileName: configFileName }));
            }
            case 'configure': {
                return renderConfigureStep({
                    items,
                    onComplete: handleConfigureComplete,
                    onBack: () => setStep('location'),
                    onDelete: handleDeleteConfig,
                    configExists: existsSync(configPath),
                });
            }
            case 'summary': {
                return (_jsxs(Box, { flexDirection: "column", children: [_jsx(Box, { marginBottom: 1, children: _jsx(Text, { bold: true, color: colors.primary, children: "Configuration Summary" }) }), _jsxs(Box, { marginBottom: 1, flexDirection: "column", children: [_jsx(Text, { color: colors.secondary, children: "Config file:" }), _jsx(Text, { color: colors.success, children: configPath })] }), renderSummaryItems(items), _jsxs(Box, { marginTop: 1, flexDirection: "column", children: [_jsx(Text, { color: colors.secondary, children: "\u2022 Enter: Save configuration" }), _jsx(Text, { color: colors.secondary, children: "\u2022 Shift+Tab: Go back" }), _jsx(Text, { color: colors.secondary, children: "\u2022 Esc: Cancel" })] })] }));
            }
            case 'confirm-delete': {
                const deleteOptions = [
                    { label: 'Yes, delete the file', value: 'yes' },
                    { label: 'No, go back', value: 'no' },
                ];
                return (_jsxs(Box, { flexDirection: "column", children: [_jsx(Box, { marginBottom: 1, children: _jsx(Text, { bold: true, color: colors.error, children: "Delete Configuration?" }) }), _jsx(Box, { marginBottom: 1, children: _jsxs(Text, { children: ["Are you sure you want to delete", ' ', _jsx(Text, { color: colors.warning, children: configPath }), "?"] }) }), _jsx(Box, { marginBottom: 1, children: _jsx(Text, { children: "This action cannot be undone." }) }), _jsx(SelectInput, { items: deleteOptions, onSelect: (item) => {
                                if (item.value === 'yes') {
                                    handleConfirmDelete();
                                }
                                else {
                                    setStep('configure');
                                }
                            } })] }));
            }
            case 'saving': {
                return (_jsx(Box, { flexDirection: "column", children: _jsx(Box, { children: _jsxs(Text, { color: colors.success, children: [_jsx(Spinner, { type: "dots" }), " Saving configuration..."] }) }) }));
            }
            case 'complete': {
                return (_jsxs(Box, { flexDirection: "column", children: [_jsx(Box, { marginBottom: 1, children: _jsx(Text, { color: colors.success, bold: true, children: "\u2713 Configuration saved!" }) }), _jsx(Box, { marginBottom: 1, children: _jsxs(Text, { children: ["Saved to: ", configPath] }) }), renderCompleteExtras?.(items), _jsx(Box, { children: _jsx(Text, { color: colors.secondary, children: "Press Enter to continue" }) })] }));
            }
            default: {
                return null;
            }
        }
    };
    return (_jsxs(TitledBoxWithPreferences, { title: title, width: boxWidth, borderColor: colors.primary, paddingX: 2, paddingY: 1, flexDirection: "column", marginBottom: 1, children: [error && (_jsx(Box, { marginBottom: 1, children: _jsxs(Text, { color: colors.error, children: ["Error: ", error] }) })), renderStep(), (step === 'location' || step === 'configure' || step === 'summary') &&
                (isNarrow ? (_jsxs(Box, { marginTop: 1, flexDirection: "column", children: [_jsx(Text, { color: colors.secondary, children: "Esc: Exit wizard" }), _jsx(Text, { color: colors.secondary, children: "Shift+Tab: Go back" }), configPath && (_jsx(Text, { color: colors.secondary, children: "Ctrl+E: Edit manually" }))] })) : (_jsx(Box, { marginTop: 1, children: _jsxs(Text, { color: colors.secondary, children: ["Esc: Exit wizard | Shift+Tab: Go back", configPath && ' | Ctrl+E: Edit manually'] }) }))), step === 'summary' && (_jsx(SummaryStepActions, { onSave: handleSave, onAddItems: () => setStep('configure'), onCancel: () => onCancel?.() }))] }));
}
function SummaryStepActions({ onSave, onAddItems, onCancel, }) {
    useInput((_input, key) => {
        if (key.shift && key.tab) {
            onAddItems();
        }
        else if (key.return) {
            onSave();
        }
        else if (key.escape) {
            onCancel();
        }
    });
    return null;
}
//# sourceMappingURL=base-config-wizard.js.map