import { readFile } from 'node:fs/promises';
import { join } from 'node:path';
import { atomicWriteJson } from '../fs/io.js';
import { parseJsonConfig } from './json.js';
import { DEFAULT_SYNC_CONFIG, loadSyncConfig, mergeKnownStrays, saveSyncConfig, } from './sync-config.js';
const DEFAULT_DEPENDENCIES = {
    readFile,
    atomicWriteJson,
    loadSyncConfig: (path) => loadSyncConfig(path, DEFAULT_SYNC_CONFIG),
    saveSyncConfig,
};
export function getUserSyncConfigPath(userConfigDir) {
    return join(userConfigDir, 'sync', 'config.json');
}
export async function resolveUserSyncConfig(userConfigDir, overrides = {}) {
    const dependencies = {
        ...DEFAULT_DEPENDENCIES,
        ...overrides,
    };
    const legacyConfigPath = join(userConfigDir, 'config.json');
    const syncConfigPath = getUserSyncConfigPath(userConfigDir);
    const syncConfig = await dependencies.loadSyncConfig(syncConfigPath);
    const legacyConfig = await readLegacyConfig(legacyConfigPath, dependencies.readFile);
    if (!legacyConfig || !hasOwn(legacyConfig, 'knownStrays')) {
        return syncConfig;
    }
    const legacyKnownStrays = Array.isArray(legacyConfig.knownStrays)
        ? legacyConfig.knownStrays.filter((value) => typeof value === 'string')
        : [];
    const migratedSyncConfig = await dependencies.saveSyncConfig(syncConfigPath, {
        ...syncConfig,
        knownStrays: mergeKnownStrays(syncConfig.knownStrays, legacyKnownStrays),
    });
    const { knownStrays: _legacyKnownStrays, ...preservedLegacyConfig } = legacyConfig;
    await dependencies.atomicWriteJson(legacyConfigPath, preservedLegacyConfig);
    return migratedSyncConfig;
}
async function readLegacyConfig(configPath, read) {
    try {
        const parsed = parseJsonConfig(await read(configPath, 'utf8'), configPath);
        return isRecord(parsed) ? parsed : null;
    }
    catch (error) {
        if (isMissingFileError(error)) {
            return null;
        }
        throw error;
    }
}
function isRecord(value) {
    return typeof value === 'object' && value !== null && !Array.isArray(value);
}
function hasOwn(value, key) {
    return Object.prototype.hasOwnProperty.call(value, key);
}
function isMissingFileError(error) {
    return (typeof error === 'object' &&
        error !== null &&
        'code' in error &&
        error.code === 'ENOENT');
}
