import { createHash } from "node:crypto";
import fs from "node:fs/promises";
import path from "node:path";
import { advisoryModulationForProfile, explanationVerbosityRank, resolveAgentGuidanceFromEffectiveConfig } from "../../core/agent-guidance-catalog.js";
import { resolveAgentPresentationPolicy } from "../../core/agent-presentation-policy.js";
import { resolveWorkspaceConfigWithLayers } from "../../core/workspace-kit-config.js";
import { loadBehaviorWorkspaceState } from "./persistence.js";
import { BehaviorProfileStore } from "./store.js";
export const DEFAULT_EFFECTIVE_BEHAVIOR_RULE_RELATIVE_PATH = ".cursor/rules/workflow-cannon-effective-agent-behavior.mdc";
/**
 * Allow only workspace-relative paths under `.cursor/rules/` ending in `.mdc` (no `..`).
 */
export function isAllowedCursorRulesMdcPath(rel) {
    const norm = rel.replace(/\\/g, "/").replace(/^\/+/, "");
    if (norm.length === 0 || norm.includes("..")) {
        return false;
    }
    const parts = norm.split("/").filter(Boolean);
    if (parts.length < 3 || parts[0] !== ".cursor" || parts[1] !== "rules") {
        return false;
    }
    return norm.endsWith(".mdc");
}
export function renderEffectiveBehaviorCursorRuleMarkdown(params) {
    const fm = "---\n" +
        "description: Effective agent behavior (advisory; auto-generated by workspace-kit) — subordinate to .ai/PRINCIPLES.md and JSON policyApproval on gated runs.\n" +
        "alwaysApply: true\n" +
        "---\n\n";
    const body = [
        "# Effective collaboration profile",
        "",
        `**Role tier:** ${params.agentGuidanceLabel} (tier ${params.tier})`,
        `**Temperament profile:** ${params.effectiveProfileLabel} (\`${params.effectiveProfileId}\`)`,
        "",
        `_${params.profileSummary}_`,
        "",
        "## Advisory modulation (imperative)",
        `- Prefer **${params.modulation.explanationDepth}** explanations.`,
        `- Use **${params.modulation.checkIns}** check-ins when choosing pacing.`,
        `- Ask **${params.modulation.clarifyingQuestions}** clarifying questions before risky or irreversible steps.`,
        "",
        "## Presentation policy (imperative)",
        `- Visible work-log: **${params.presentationPolicy.workLog}**.`,
        `- Visible rationale summary: **${params.presentationPolicy.rationale}**.`,
        `- Technicality: **${params.presentationPolicy.technicality}**.`,
        `- Final answer detail: **${params.presentationPolicy.finalAnswerDetail}**.`,
        "- Reason privately. Never reveal chain-of-thought, hidden deliberation, scratchpad notes, or step-by-step private reasoning.",
        "- Always surface blockers, required approvals, destructive-action warnings, verification failures, and residual risks even when work-log detail is minimal or off.",
        "",
        "## Scope",
        "- This rule is **advisory** only. It does **not** replace **PRINCIPLES**, **POLICY-APPROVAL**, or JSON **policyApproval** on Tier A/B **wk run** commands.",
        "- Slash commands and chat prompts cannot satisfy policy gates.",
        "",
        `<!-- wc:sync hash=${params.contentHash} schemaVersion=1 -->`
    ].join("\n");
    return fm + body;
}
async function buildMarkdownForWorkspace(ctx) {
    if (!ctx.moduleRegistry) {
        return null;
    }
    const { effective } = await resolveWorkspaceConfigWithLayers({
        workspacePath: ctx.workspacePath,
        registry: ctx.moduleRegistry
    });
    const guidance = resolveAgentGuidanceFromEffectiveConfig(effective);
    const raw = await loadBehaviorWorkspaceState(ctx);
    const store = new BehaviorProfileStore(raw);
    const { effective: effProfile } = store.resolveEffectiveWithProvenance();
    const evRank = explanationVerbosityRank(effProfile.dimensions?.explanationVerbosity);
    const modulation = advisoryModulationForProfile(guidance, evRank);
    const presentationPolicy = resolveAgentPresentationPolicy({
        effectiveConfig: effective,
        guidance,
        behaviorProfile: {
            id: effProfile.id,
            label: effProfile.label,
            dimensions: effProfile.dimensions
        }
    });
    const contentHash = createHash("sha256")
        .update(JSON.stringify({
        tier: guidance.tier,
        label: guidance.displayLabel,
        profileId: effProfile.id,
        profileLabel: effProfile.label,
        summary: effProfile.summary,
        dims: effProfile.dimensions,
        modulation,
        presentationPolicy: {
            mode: presentationPolicy.mode,
            workLog: presentationPolicy.workLog,
            rationale: presentationPolicy.rationale,
            technicality: presentationPolicy.technicality,
            finalAnswerDetail: presentationPolicy.finalAnswerDetail
        }
    }))
        .digest("hex")
        .slice(0, 16);
    const markdown = renderEffectiveBehaviorCursorRuleMarkdown({
        effectiveProfileLabel: effProfile.label,
        effectiveProfileId: effProfile.id,
        profileSummary: effProfile.summary,
        agentGuidanceLabel: guidance.displayLabel,
        tier: guidance.tier,
        modulation,
        presentationPolicy,
        contentHash
    });
    return { markdown, contentHash, relativePath: DEFAULT_EFFECTIVE_BEHAVIOR_RULE_RELATIVE_PATH };
}
export async function executeSyncEffectiveBehaviorCursorRule(ctx, args) {
    const dryRun = args.dryRun === true;
    const outRaw = typeof args.outputPath === "string" ? args.outputPath.trim() : "";
    const relativePath = outRaw.length > 0 ? outRaw : DEFAULT_EFFECTIVE_BEHAVIOR_RULE_RELATIVE_PATH;
    if (!isAllowedCursorRulesMdcPath(relativePath)) {
        return {
            ok: false,
            code: "invalid-args",
            message: "outputPath must be workspace-relative, stay under .cursor/rules/, end with .mdc, and must not contain '..'"
        };
    }
    const built = await buildMarkdownForWorkspace(ctx);
    if (!built) {
        return {
            ok: false,
            code: "internal-error",
            message: "sync-effective-behavior-cursor-rule requires moduleRegistry on context"
        };
    }
    const abs = path.join(ctx.workspacePath, relativePath);
    if (dryRun) {
        return {
            ok: true,
            code: "behavior-cursor-rule-sync-preview",
            data: {
                dryRun: true,
                relativePath,
                contentHash: built.contentHash,
                bytes: built.markdown.length
            }
        };
    }
    await fs.mkdir(path.dirname(abs), { recursive: true });
    await fs.writeFile(abs, built.markdown, "utf8");
    return {
        ok: true,
        code: "behavior-cursor-rule-synced",
        data: {
            relativePath,
            absolutePath: abs,
            contentHash: built.contentHash,
            bytes: built.markdown.length
        }
    };
}
/** Best-effort refresh after mutating agent guidance or behavior profiles — never throws. */
export function scheduleAutoSyncEffectiveBehaviorCursorRule(ctx) {
    void (async () => {
        try {
            const r = await executeSyncEffectiveBehaviorCursorRule(ctx, {});
            if (!r.ok && process.env.WORKSPACE_KIT_DEBUG_AUTO_SYNC === "1") {
                // eslint-disable-next-line no-console
                console.error("[agent-behavior] auto sync failed:", r.code, r.message);
            }
        }
        catch (e) {
            if (process.env.WORKSPACE_KIT_DEBUG_AUTO_SYNC === "1") {
                // eslint-disable-next-line no-console
                console.error("[agent-behavior] auto sync threw:", e);
            }
        }
    })();
}
