import { existsSync } from 'node:fs';
import { homedir } from 'node:os';
import { dirname, isAbsolute, join, relative, resolve, sep } from 'node:path';
import { CONFIG_DIR_NAME } from '../../config.js';
import { loadSkillsFromDir } from './skills.js';
function normalizeSettingsPath(input, homeDir) {
    const trimmed = input.trim();
    if (trimmed === '~')
        return homeDir;
    if (trimmed.startsWith('~/'))
        return join(homeDir, trimmed.slice(2));
    if (trimmed.startsWith('~'))
        return join(homeDir, trimmed.slice(1));
    return trimmed;
}
function resolveSettingsPath(input, scope, cwd, agentDir, homeDir) {
    const normalized = normalizeSettingsPath(input, homeDir);
    if (isAbsolute(normalized)) {
        return resolve(normalized);
    }
    const baseDir = scope === 'project' ? join(cwd, CONFIG_DIR_NAME) : agentDir;
    return resolve(baseDir, normalized);
}
function toSettingsPath(path, scope, cwd, agentDir, homeDir) {
    const resolved = resolve(path);
    if (scope === 'user') {
        if (resolved === homeDir)
            return '~';
        const prefix = homeDir.endsWith(sep) ? homeDir : `${homeDir}${sep}`;
        if (resolved.startsWith(prefix)) {
            return `~/${relative(homeDir, resolved).split(sep).join('/')}`;
        }
        return resolved;
    }
    const baseDir = join(cwd, CONFIG_DIR_NAME);
    const rel = relative(baseDir, resolved);
    if (!rel)
        return '.';
    if (rel.includes(':'))
        return resolved;
    return rel.split(sep).join('/');
}
function findGitRepoRoot(startDir) {
    let dir = resolve(startDir);
    while (true) {
        if (existsSync(join(dir, '.git'))) {
            return dir;
        }
        const parent = dirname(dir);
        if (parent === dir) {
            return null;
        }
        dir = parent;
    }
}
function collectProjectCandidateRoots(startDir) {
    const candidates = [];
    const repoRoot = findGitRepoRoot(startDir);
    let dir = resolve(startDir);
    while (true) {
        candidates.push({
            provider: 'agents',
            scope: 'project',
            rootPath: join(dir, '.agents', 'skills')
        });
        candidates.push({
            provider: 'claude',
            scope: 'project',
            rootPath: join(dir, '.claude', 'skills')
        });
        candidates.push({
            provider: 'codex',
            scope: 'project',
            rootPath: join(dir, '.codex', 'skills')
        });
        if (repoRoot && dir === repoRoot) {
            break;
        }
        const parent = dirname(dir);
        if (parent === dir) {
            break;
        }
        dir = parent;
    }
    return candidates;
}
function collectUserCandidateRoots(homeDir) {
    return [
        { provider: 'agents', scope: 'user', rootPath: join(homeDir, '.agents', 'skills') },
        { provider: 'claude', scope: 'user', rootPath: join(homeDir, '.claude', 'skills') },
        { provider: 'codex', scope: 'user', rootPath: join(homeDir, '.codex', 'skills') }
    ];
}
export function inferExternalSkillProviderFromPath(path) {
    const normalized = resolve(path).split(sep).join('/');
    if (normalized.includes('/.agents/skills'))
        return 'agents';
    if (normalized.includes('/.claude/skills'))
        return 'claude';
    if (normalized.includes('/.codex/skills'))
        return 'codex';
    return null;
}
export function getExternalSkillProviderLabel(provider) {
    switch (provider) {
        case 'agents':
            return 'Agents';
        case 'claude':
            return 'Claude';
        case 'codex':
            return 'Codex';
    }
}
export function discoverExternalSkillRoots(options) {
    const { cwd, agentDir, settingsManager } = options;
    const homeDir = options.homeDir ?? homedir();
    const discovered = new Map();
    const registeredPaths = new Set();
    for (const entry of settingsManager.getGlobalSettings().skills ?? []) {
        registeredPaths.add(resolveSettingsPath(entry, 'user', cwd, agentDir, homeDir));
    }
    for (const entry of settingsManager.getProjectSettings().skills ?? []) {
        registeredPaths.add(resolveSettingsPath(entry, 'project', cwd, agentDir, homeDir));
    }
    for (const candidate of [
        ...collectProjectCandidateRoots(cwd),
        ...collectUserCandidateRoots(homeDir)
    ]) {
        const rootPath = resolve(candidate.rootPath);
        if (!existsSync(rootPath))
            continue;
        if (discovered.has(rootPath))
            continue;
        const result = loadSkillsFromDir({ dir: rootPath, source: 'path' });
        const brokenSkillPaths = new Set(result.diagnostics
            .map((diagnostic) => diagnostic.path)
            .filter((path) => typeof path === 'string'));
        discovered.set(rootPath, {
            provider: candidate.provider,
            scope: candidate.scope,
            rootPath,
            settingsPath: toSettingsPath(rootPath, candidate.scope, cwd, agentDir, homeDir),
            validSkillCount: result.skills.length,
            brokenSkillCount: brokenSkillPaths.size,
            skillNames: result.skills.map((skill) => skill.name).sort((a, b) => a.localeCompare(b)),
            warnings: result.diagnostics.map((diagnostic) => ({
                path: diagnostic.path,
                message: diagnostic.message
            })),
            alreadyRegistered: registeredPaths.has(rootPath)
        });
    }
    for (const entry of settingsManager.getGlobalSettings().skills ?? []) {
        const rootPath = resolveSettingsPath(entry, 'user', cwd, agentDir, homeDir);
        const provider = inferExternalSkillProviderFromPath(rootPath);
        if (!provider || discovered.has(rootPath)) {
            continue;
        }
        discovered.set(rootPath, {
            provider,
            scope: 'user',
            rootPath,
            settingsPath: entry,
            validSkillCount: 0,
            brokenSkillCount: 1,
            skillNames: [],
            warnings: [{ path: rootPath, message: 'Registered root is missing or unavailable.' }],
            alreadyRegistered: true
        });
    }
    for (const entry of settingsManager.getProjectSettings().skills ?? []) {
        const rootPath = resolveSettingsPath(entry, 'project', cwd, agentDir, homeDir);
        const provider = inferExternalSkillProviderFromPath(rootPath);
        if (!provider || discovered.has(rootPath)) {
            continue;
        }
        discovered.set(rootPath, {
            provider,
            scope: 'project',
            rootPath,
            settingsPath: entry,
            validSkillCount: 0,
            brokenSkillCount: 1,
            skillNames: [],
            warnings: [{ path: rootPath, message: 'Registered root is missing or unavailable.' }],
            alreadyRegistered: true
        });
    }
    return Array.from(discovered.values()).sort((a, b) => {
        if (a.scope !== b.scope)
            return a.scope === 'project' ? -1 : 1;
        if (a.provider !== b.provider)
            return a.provider.localeCompare(b.provider);
        return a.rootPath.localeCompare(b.rootPath);
    });
}
export function registerExternalSkillRoots(options) {
    const { discoveries, cwd, agentDir, settingsManager } = options;
    const homeDir = options.homeDir ?? homedir();
    const result = {
        registered: [],
        alreadyRegistered: [],
        skippedNoValidSkills: []
    };
    const nextUserPaths = [...(settingsManager.getGlobalSettings().skills ?? [])];
    const nextProjectPaths = [...(settingsManager.getProjectSettings().skills ?? [])];
    const existingUserPaths = new Set(nextUserPaths.map((entry) => resolveSettingsPath(entry, 'user', cwd, agentDir, homeDir)));
    const existingProjectPaths = new Set(nextProjectPaths.map((entry) => resolveSettingsPath(entry, 'project', cwd, agentDir, homeDir)));
    for (const discovery of discoveries) {
        if (discovery.validSkillCount === 0) {
            result.skippedNoValidSkills.push(discovery);
            continue;
        }
        const existing = discovery.scope === 'project' ? existingProjectPaths : existingUserPaths;
        if (discovery.alreadyRegistered || existing.has(discovery.rootPath)) {
            result.alreadyRegistered.push(discovery);
            continue;
        }
        if (discovery.scope === 'project') {
            nextProjectPaths.push(discovery.settingsPath);
            existingProjectPaths.add(discovery.rootPath);
        }
        else {
            nextUserPaths.push(discovery.settingsPath);
            existingUserPaths.add(discovery.rootPath);
        }
        result.registered.push(discovery);
    }
    if (result.registered.some((entry) => entry.scope === 'user')) {
        settingsManager.setSkillPaths(nextUserPaths);
    }
    if (result.registered.some((entry) => entry.scope === 'project')) {
        settingsManager.setProjectSkillPaths(nextProjectPaths);
    }
    return result;
}
export function syncExternalSkillRoots(options) {
    const { discoveries, cwd, agentDir, settingsManager } = options;
    const homeDir = options.homeDir ?? homedir();
    const desiredActive = new Set(options.activeRootPaths.map((path) => resolve(path)));
    const result = {
        activated: [],
        deactivated: [],
        unchanged: [],
        skippedNoValidSkills: []
    };
    const nextUserPaths = [...(settingsManager.getGlobalSettings().skills ?? [])];
    const nextProjectPaths = [...(settingsManager.getProjectSettings().skills ?? [])];
    const syncScope = (scope, paths, discoveriesForScope) => {
        const indexed = new Map(discoveriesForScope.map((entry) => [resolve(entry.rootPath), entry]));
        let changed = false;
        const keptPaths = [];
        for (const pathEntry of paths) {
            const resolved = resolveSettingsPath(pathEntry, scope, cwd, agentDir, homeDir);
            const discovery = indexed.get(resolved);
            if (!discovery) {
                keptPaths.push(pathEntry);
                continue;
            }
            if (desiredActive.has(resolved)) {
                keptPaths.push(pathEntry);
                result.unchanged.push(discovery);
            }
            else {
                changed = true;
                result.deactivated.push(discovery);
            }
            indexed.delete(resolved);
        }
        for (const discovery of indexed.values()) {
            if (!desiredActive.has(discovery.rootPath)) {
                result.unchanged.push(discovery);
                continue;
            }
            if (discovery.validSkillCount === 0) {
                result.skippedNoValidSkills.push(discovery);
                continue;
            }
            keptPaths.push(discovery.settingsPath);
            changed = true;
            result.activated.push(discovery);
        }
        return { nextPaths: keptPaths, changed };
    };
    const userSync = syncScope('user', nextUserPaths, discoveries.filter((entry) => entry.scope === 'user'));
    const projectSync = syncScope('project', nextProjectPaths, discoveries.filter((entry) => entry.scope === 'project'));
    if (userSync.changed) {
        settingsManager.setSkillPaths(userSync.nextPaths);
    }
    if (projectSync.changed) {
        settingsManager.setProjectSkillPaths(projectSync.nextPaths);
    }
    return result;
}
//# sourceMappingURL=external-skill-roots.js.map