/*
 * Copyright 2026, Jaime Terrats.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
import { existsSync, lstatSync, mkdirSync, readdirSync, readlinkSync, rmSync, symlinkSync, unlinkSync } from 'node:fs';
import { basename, join } from 'node:path';
import { SfError, Messages } from '@salesforce/core';
import { Flags, SfCommand } from '@salesforce/sf-plugins-core';
import { findSourceCanvases, isCanvasToolActive, resolveCacheDir, resolveProjectDir, } from '../../../util/canvas-helpers.js';
Messages.importMessagesDirectoryFromMetaUrl(import.meta.url);
const messages = Messages.loadMessages('@jterrats/setup-agents', 'setup-agents.canvas.sync');
export default class CanvasSync extends SfCommand {
    static summary = messages.getMessage('summary');
    static description = messages.getMessage('description');
    static examples = messages.getMessages('examples');
    static flags = {
        'dry-run': Flags.boolean({
            summary: messages.getMessage('flags.dry-run.summary'),
            default: false,
        }),
        init: Flags.boolean({
            summary: messages.getMessage('flags.init.summary'),
            default: false,
        }),
        clean: Flags.boolean({
            summary: messages.getMessage('flags.clean.summary'),
            default: false,
        }),
        path: Flags.string({
            summary: messages.getMessage('flags.path.summary'),
        }),
    };
    async run() {
        const { flags } = await this.parse(CanvasSync);
        const cwd = flags.path ?? process.cwd();
        const dryRun = flags['dry-run'];
        if (!isCanvasToolActive(cwd)) {
            this.warn(messages.getMessage('warn.cursorNotActive'));
            return { synced: 0, alreadyOk: 0, orphansRemoved: 0, cacheDir: '', dryRun, cwd };
        }
        const projectDir = resolveProjectDir(cwd);
        const cacheDir = resolveCacheDir(projectDir);
        ensureCacheDir(cacheDir, flags.init, dryRun);
        const sources = findSourceCanvases(projectDir);
        if (sources.length === 0) {
            throw new SfError(messages.getMessage('error.noSources', [projectDir]));
        }
        let synced = 0;
        let alreadyOk = 0;
        for (const src of sources) {
            const result = syncSourceLink(src, cacheDir, dryRun);
            if (result.action === 'skip') {
                alreadyOk++;
            }
            else {
                this.log(result.message);
                synced++;
            }
        }
        const orphans = findOrphans(cacheDir, sources);
        const orphansRemoved = cleanOrphans(orphans, flags.clean, dryRun, this);
        if (dryRun) {
            this.log(messages.getMessage('info.dryRunSummary', [String(synced), String(alreadyOk), String(orphans.length)]));
        }
        else {
            this.log(messages.getMessage('info.summary', [String(synced), String(alreadyOk)]));
        }
        return { synced, alreadyOk, orphansRemoved, cacheDir, dryRun, cwd };
    }
}
function ensureCacheDir(cacheDir, init, dryRun) {
    if (existsSync(cacheDir))
        return;
    if (!init) {
        throw new SfError(messages.getMessage('error.noCacheDir', [cacheDir]));
    }
    if (!dryRun) {
        mkdirSync(cacheDir, { recursive: true });
    }
}
function syncSourceLink(src, cacheDir, dryRun) {
    const name = basename(src);
    const cachePath = join(cacheDir, name);
    if (isCorrectSymlink(cachePath, src)) {
        return { action: 'skip' };
    }
    if (dryRun) {
        return { action: 'linked', message: messages.getMessage('info.dryRunLink', [cachePath, src]) };
    }
    if (existsSync(cachePath) || isSymlink(cachePath)) {
        unlinkSync(cachePath);
    }
    symlinkSync(src, cachePath);
    return { action: 'linked', message: messages.getMessage('info.linked', [name, src]) };
}
function cleanOrphans(orphans, clean, dryRun, cmd) {
    if (!clean) {
        for (const orphan of orphans) {
            cmd.warn(messages.getMessage('warn.orphan', [basename(orphan)]));
        }
        return 0;
    }
    let removed = 0;
    for (const orphan of orphans) {
        if (dryRun) {
            cmd.log(`[dry-run] would remove orphan: ${orphan}`);
        }
        else {
            rmSync(orphan, { force: true });
            const statusFile = orphan.replace(/\.tsx$/, '.status.json');
            rmSync(statusFile, { force: true });
        }
        removed++;
    }
    return removed;
}
// ─── Symlink utilities ───────────────────────────────────────────────────────
function isCorrectSymlink(filePath, expectedTarget) {
    try {
        const stat = lstatSync(filePath);
        if (!stat.isSymbolicLink())
            return false;
        return readlinkSync(filePath) === expectedTarget;
    }
    catch {
        return false;
    }
}
function isSymlink(filePath) {
    try {
        return lstatSync(filePath).isSymbolicLink();
    }
    catch {
        return false;
    }
}
function findOrphans(cacheDir, sources) {
    if (!existsSync(cacheDir))
        return [];
    const sourceNames = new Set(sources.map((s) => basename(s)));
    return readdirSync(cacheDir)
        .filter((f) => f.endsWith('.canvas.tsx'))
        .map((f) => join(cacheDir, f))
        .filter((f) => !sourceNames.has(basename(f)));
}
//# sourceMappingURL=sync.js.map