import { existsSync, readFileSync } from 'node:fs';
import { mkdir, rename, writeFile } from 'node:fs/promises';
import { homedir } from 'node:os';
import { dirname, join } from 'node:path';
import { z } from 'zod';
import { languageSchema } from '../../modules/shared-kernel/entities/language/language.schema.js';
export const claudeModelSchema = z.enum(['haiku', 'sonnet', 'opus']);
const worktreeStaleThresholdHoursSchema = z.number().int().min(1).max(720);
const runtimeSettingsSchema = z.object({
    language: languageSchema,
    model: claudeModelSchema,
    worktreeStaleThresholdHours: worktreeStaleThresholdHoursSchema.default(24),
});
const DEFAULT_SETTINGS = {
    model: 'opus',
    language: 'en',
    worktreeStaleThresholdHours: 24,
};
let settings = { ...DEFAULT_SETTINGS };
let settingsPath = null;
let logger = { warn: (message) => console.warn(message) };
let writeQueue = Promise.resolve();
export function getDefaultSettingsPath() {
    return join(homedir(), '.claude-review', 'settings.json');
}
export function configureSettingsPath(path) {
    settingsPath = path;
}
export function configureSettingsLogger(injected) {
    logger = injected;
}
export async function loadSettingsFromDisk() {
    if (!settingsPath)
        return;
    if (!existsSync(settingsPath)) {
        settings = { ...DEFAULT_SETTINGS };
        await persistAsync();
        return;
    }
    let raw;
    try {
        raw = readFileSync(settingsPath, 'utf-8');
    }
    catch (error) {
        const reason = error instanceof Error ? error.message : String(error);
        logger.warn(`[runtimeSettings] failed to read settings file at ${settingsPath}: ${reason}; using defaults`);
        settings = { ...DEFAULT_SETTINGS };
        return;
    }
    let parsed;
    try {
        parsed = JSON.parse(raw);
    }
    catch {
        logger.warn(`[runtimeSettings] malformed JSON at ${settingsPath}; using defaults`);
        settings = { ...DEFAULT_SETTINGS };
        return;
    }
    const result = runtimeSettingsSchema.safeParse(parsed);
    if (!result.success) {
        logger.warn(`[runtimeSettings] invalid settings at ${settingsPath}; using defaults`);
        settings = { ...DEFAULT_SETTINGS };
        return;
    }
    settings = result.data;
}
async function writeAtomically(path, payload) {
    const temporaryPath = `${path}.tmp`;
    await mkdir(dirname(path), { recursive: true });
    await writeFile(temporaryPath, payload, 'utf-8');
    await rename(temporaryPath, path);
}
function persistAsync() {
    if (!settingsPath)
        return Promise.resolve();
    const path = settingsPath;
    const enqueue = writeQueue.then(() => writeAtomically(path, JSON.stringify(settings, null, 2)), () => writeAtomically(path, JSON.stringify(settings, null, 2)));
    writeQueue = enqueue;
    return enqueue;
}
export function getModel() {
    return settings.model;
}
export async function setModel(model) {
    const result = claudeModelSchema.safeParse(model);
    if (!result.success) {
        throw new Error(`Invalid model: ${model}`);
    }
    settings.model = result.data;
    await persistAsync();
}
export function getDefaultLanguage() {
    return settings.language;
}
export async function setDefaultLanguage(language) {
    const result = languageSchema.safeParse(language);
    if (!result.success) {
        throw new Error(`Invalid language: ${language}`);
    }
    settings.language = result.data;
    await persistAsync();
}
export function getWorktreeStaleThresholdHours() {
    return settings.worktreeStaleThresholdHours;
}
export async function setWorktreeStaleThresholdHours(hours) {
    const result = worktreeStaleThresholdHoursSchema.safeParse(hours);
    if (!result.success) {
        throw new Error(`Invalid stale threshold (hours): ${hours}`);
    }
    settings.worktreeStaleThresholdHours = result.data;
    await persistAsync();
}
export function getSettings() {
    return { ...settings };
}
/**
 * Test-only helper. Resets module-level state (settings, path, logger, write queue).
 * Exposed because this module owns module-level mutable state; production code must
 * never call this. A proper fix would extract a SettingsRepository class with
 * constructor-injected dependencies; see PR #221 review for context.
 */
export function __resetForTestsOnly() {
    settings = { ...DEFAULT_SETTINGS };
    settingsPath = null;
    logger = { warn: (message) => console.warn(message) };
    writeQueue = Promise.resolve();
}
//# sourceMappingURL=runtimeSettings.js.map