import fs from "node:fs/promises";
import path from "node:path";
import { fileURLToPath } from "node:url";
import { allowedPackageManagers, currentOwnedPaths, pointerRuleContent, profileSchemaContent } from "./profile-baseline-content.js";
import { CANONICAL_KIT_NAME, defaultWorkspaceKitPaths } from "./default-workspace-kit-paths.js";
export async function parseJsonFile(filePath) {
    const raw = await fs.readFile(filePath, "utf8");
    return JSON.parse(raw);
}
function readStringField(objectValue, key, errors, fieldPath) {
    const value = objectValue[key];
    if (typeof value !== "string" || value.trim().length === 0) {
        errors.push(`${fieldPath} must be a non-empty string`);
        return undefined;
    }
    return value;
}
export async function validateProfile(cwd) {
    const profilePath = path.join(cwd, defaultWorkspaceKitPaths.profile);
    const errors = [];
    let profile;
    try {
        profile = await parseJsonFile(profilePath);
    }
    catch {
        return { errors: [`${defaultWorkspaceKitPaths.profile} is missing or invalid JSON`] };
    }
    if (!profile || typeof profile !== "object" || Array.isArray(profile)) {
        return { errors: ["workspace-kit profile root must be an object"] };
    }
    const profileObject = profile;
    const project = profileObject.project;
    const commands = profileObject.commands;
    const github = profileObject.github;
    const packageManager = profileObject.packageManager;
    if (!project || typeof project !== "object" || Array.isArray(project)) {
        errors.push("project must be an object");
    }
    else {
        readStringField(project, "name", errors, "project.name");
    }
    if (typeof packageManager !== "string" || !allowedPackageManagers.has(packageManager)) {
        errors.push("packageManager must be one of: pnpm, npm, yarn");
    }
    if (!commands || typeof commands !== "object" || Array.isArray(commands)) {
        errors.push("commands must be an object");
    }
    else {
        const commandsObject = commands;
        readStringField(commandsObject, "test", errors, "commands.test");
        readStringField(commandsObject, "lint", errors, "commands.lint");
        readStringField(commandsObject, "typecheck", errors, "commands.typecheck");
    }
    if (!github || typeof github !== "object" || Array.isArray(github)) {
        errors.push("github must be an object");
    }
    else {
        readStringField(github, "defaultBranch", errors, "github.defaultBranch");
    }
    if (errors.length > 0) {
        return { errors };
    }
    const validatedProject = profileObject.project;
    const validatedCommands = profileObject.commands;
    const validatedGithub = profileObject.github;
    const validatedPackageManager = profileObject.packageManager;
    return {
        errors,
        profile: {
            project: { name: validatedProject.name },
            packageManager: validatedPackageManager,
            commands: {
                test: validatedCommands.test,
                lint: validatedCommands.lint,
                typecheck: validatedCommands.typecheck
            },
            github: {
                defaultBranch: validatedGithub.defaultBranch
            }
        }
    };
}
export function toJsonWithTrailingNewline(value) {
    return `${JSON.stringify(value, null, 2)}\n`;
}
function renderProfileDrivenArtifacts(profile) {
    const generatedContext = {
        generatedFrom: defaultWorkspaceKitPaths.profile,
        projectName: profile.project.name,
        packageManager: profile.packageManager,
        commands: profile.commands,
        github: profile.github
    };
    const generatedRuleText = [
        "# Workspace Kit Project Context (Generated)",
        "",
        "This file is generated by `workspace-kit refresh-context` (after editing `workspace-kit.profile.json`).",
        "Do not hand-edit project identity values here; update `workspace-kit.profile.json` and rerun init.",
        "",
        `- project_name: ${profile.project.name}`,
        `- package_manager: ${profile.packageManager}`,
        `- default_branch: ${profile.github.defaultBranch}`,
        `- test_command: ${profile.commands.test}`,
        `- lint_command: ${profile.commands.lint}`,
        `- typecheck_command: ${profile.commands.typecheck}`,
        "",
        "When instructions need project-specific values, prefer this generated file or `.workspace-kit/generated/project-context.json`."
    ].join("\n");
    return {
        generatedContextJson: toJsonWithTrailingNewline(generatedContext),
        generatedRuleText: `${generatedRuleText}\n`
    };
}
export async function generateProfileDrivenArtifacts(cwd, profile) {
    const generatedJsonPath = path.join(cwd, ".workspace-kit", "generated", "project-context.json");
    const generatedRulePath = path.join(cwd, ".cursor", "rules", "workspace-kit-project-context.mdc");
    const renderedArtifacts = renderProfileDrivenArtifacts(profile);
    await fs.mkdir(path.dirname(generatedJsonPath), { recursive: true });
    await fs.writeFile(generatedJsonPath, renderedArtifacts.generatedContextJson, "utf8");
    await fs.mkdir(path.dirname(generatedRulePath), { recursive: true });
    await fs.writeFile(generatedRulePath, renderedArtifacts.generatedRuleText, "utf8");
    return { generatedJsonPath, generatedRulePath };
}
export function createDriftExpectedAssets(profile) {
    const generated = renderProfileDrivenArtifacts(profile);
    return new Map([
        [defaultWorkspaceKitPaths.profileSchema, toJsonWithTrailingNewline(profileSchemaContent)],
        [".cursor/rules/workspace-kit-profile-pointer.mdc", pointerRuleContent],
        [".workspace-kit/generated/project-context.json", generated.generatedContextJson],
        [".cursor/rules/workspace-kit-project-context.mdc", generated.generatedRuleText]
    ]);
}
export function driftContentMatches(relativePath, existingContent, expectedContent) {
    if (!relativePath.endsWith(".json")) {
        return existingContent === expectedContent;
    }
    try {
        const existingJson = JSON.parse(existingContent);
        const expectedJson = JSON.parse(expectedContent);
        return JSON.stringify(existingJson) === JSON.stringify(expectedJson);
    }
    catch {
        return existingContent === expectedContent;
    }
}
export async function resolvePackageVersion(cwd) {
    const candidatePaths = [
        path.join(cwd, "packages", "workspace-kit", "package.json"),
        path.join(cwd, "package.json")
    ];
    for (const candidatePath of candidatePaths) {
        try {
            const parsed = await parseJsonFile(candidatePath);
            if (parsed && typeof parsed === "object" && !Array.isArray(parsed)) {
                const version = parsed.version;
                const name = parsed.name;
                if (typeof version === "string" && version.length > 0 && typeof name === "string") {
                    if (name === CANONICAL_KIT_NAME ||
                        name === "quicktask-workspace-kit" ||
                        candidatePath.endsWith("packages/workspace-kit/package.json")) {
                        return version;
                    }
                }
            }
        }
        catch {
            continue;
        }
    }
    return undefined;
}
/** Version from the installed kit package (works from repo `dist/` or `node_modules`). */
export async function readCliBundledPackageVersion() {
    try {
        const pkgPath = path.join(path.dirname(fileURLToPath(import.meta.url)), "..", "..", "package.json");
        const parsed = await parseJsonFile(pkgPath);
        if (parsed && typeof parsed === "object" && !Array.isArray(parsed)) {
            const v = parsed.version;
            return typeof v === "string" && v.length > 0 ? v : undefined;
        }
    }
    catch {
        /* ignore */
    }
    return undefined;
}
export async function readOwnedPathsDocument(cwd) {
    const ownedPathsPath = path.join(cwd, defaultWorkspaceKitPaths.ownedPaths);
    let parsed;
    try {
        parsed = await parseJsonFile(ownedPathsPath);
    }
    catch {
        return {
            schemaVersion: 1,
            ownedPaths: currentOwnedPaths,
            notes: "Owned path policy fallback generated by workspace-kit upgrade."
        };
    }
    if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) {
        return {
            schemaVersion: 1,
            ownedPaths: currentOwnedPaths,
            notes: "Owned path policy fallback generated by workspace-kit upgrade."
        };
    }
    const value = parsed;
    const ownedPaths = Array.isArray(value.ownedPaths)
        ? value.ownedPaths.filter((item) => typeof item === "string")
        : [];
    return {
        schemaVersion: typeof value.schemaVersion === "number" ? value.schemaVersion : 1,
        ownedPaths: ownedPaths.length > 0 ? ownedPaths : currentOwnedPaths,
        notes: typeof value.notes === "string" ? value.notes : undefined
    };
}
export async function writeFileWithBackupIfChanged(cwd, relativePath, content, backupRoot) {
    const targetPath = path.join(cwd, relativePath);
    let existingContent;
    try {
        existingContent = await fs.readFile(targetPath, "utf8");
    }
    catch {
        existingContent = undefined;
    }
    if (existingContent === content) {
        return false;
    }
    if (typeof existingContent === "string") {
        const backupPath = path.join(backupRoot, `${relativePath}.bak`);
        await fs.mkdir(path.dirname(backupPath), { recursive: true });
        await fs.writeFile(backupPath, existingContent, "utf8");
    }
    await fs.mkdir(path.dirname(targetPath), { recursive: true });
    await fs.writeFile(targetPath, content, "utf8");
    return true;
}
