import { inferTaskPhaseKey } from "./phase-resolution.js";
import { DEFAULT_MAINTAINER_DELIVERY_POLICY, TASK_POLICY_OVERRIDE_PRECEDENCE } from "./policy-config.js";
import { MAINTAINER_DELIVERY_PROFILE_METADATA_KEY, REQUIRES_PHASE_BRANCH_METADATA_KEY } from "./maintainer-delivery-metadata-keys.js";
import { readDeliveryEvidenceEnforcementMode } from "./delivery-evidence.js";
const TOKEN_KEYS = new Set(["taskId", "slug", "phaseKey", "moduleId", "version"]);
export function deliveryEvidenceModesForMaintainerEvidenceKind(evidenceKind) {
    if (evidenceKind === "github-pr") {
        return ["github-pr"];
    }
    if (evidenceKind === "manual") {
        return ["local-reviewed-merge", "direct-reviewed-merge", "external-review"];
    }
    return undefined;
}
export function buildDeliveryEvidencePolicyContext(input) {
    return {
        allowedEvidenceModes: deliveryEvidenceModesForMaintainerEvidenceKind(input.resolvedPolicy.evidenceMode),
        requiredEvidenceMode: input.resolvedPolicy.evidenceMode,
        policyProfile: input.resolvedPolicy.profileName,
        policyWarnings: input.warnings?.map((warning) => `${warning.code}: ${warning.message}`) ?? []
    };
}
function isRecord(value) {
    return value !== null && typeof value === "object" && !Array.isArray(value);
}
function parseEnforcement(raw) {
    if (raw === "off" || raw === "advisory" || raw === "enforce") {
        return raw;
    }
    return undefined;
}
/** Merge persisted maintainerDelivery with shipped defaults (profiles + overrides). */
export function parseMaintainerDeliveryPolicyConfig(effective) {
    const raw = effective?.maintainerDelivery;
    if (!isRecord(raw)) {
        return JSON.parse(JSON.stringify(DEFAULT_MAINTAINER_DELIVERY_POLICY));
    }
    const baseProfiles = {
        ...DEFAULT_MAINTAINER_DELIVERY_POLICY.profiles,
        ...(isRecord(raw.profiles) ? raw.profiles : {})
    };
    const moduleOverrides = {};
    if (isRecord(raw.moduleOverrides)) {
        for (const [k, v] of Object.entries(raw.moduleOverrides)) {
            if (isRecord(v) && typeof v.profile === "string") {
                moduleOverrides[k] = v;
            }
        }
    }
    return {
        defaultProfile: typeof raw.defaultProfile === "string"
            ? raw.defaultProfile
            : DEFAULT_MAINTAINER_DELIVERY_POLICY.defaultProfile,
        enforcementMode: parseEnforcement(raw.enforcementMode) ?? DEFAULT_MAINTAINER_DELIVERY_POLICY.enforcementMode,
        profiles: baseProfiles,
        moduleOverrides
    };
}
export function slugifyTaskTitle(title) {
    const s = title
        .toLowerCase()
        .replace(/[^a-z0-9]+/g, "-")
        .replace(/^-+|-+$/g, "")
        .slice(0, 48);
    return s.length > 0 ? s : "task";
}
function expandTokens(pattern, ctx) {
    return pattern.replace(/\{([a-zA-Z0-9_]+)\}/g, (full, key) => {
        if (!TOKEN_KEYS.has(key)) {
            return full;
        }
        return ctx[key] ?? "";
    });
}
function normalizeProfileRecord(p) {
    const base = DEFAULT_MAINTAINER_DELIVERY_POLICY.profiles["github-pr"];
    return {
        requiresPhaseBranch: p.requiresPhaseBranch ?? base.requiresPhaseBranch,
        branchPattern: p.branchPattern ?? base.branchPattern,
        taskBranchPattern: p.taskBranchPattern ?? base.taskBranchPattern,
        releaseTagPattern: p.releaseTagPattern ?? base.releaseTagPattern,
        review: p.review ?? base.review,
        evidenceKind: p.evidenceKind ?? base.evidenceKind,
        prProvider: p.prProvider ?? base.prProvider,
        mergeStrategy: p.mergeStrategy ?? base.mergeStrategy,
        phaseToMainMode: p.phaseToMainMode ?? base.phaseToMainMode
    };
}
/**
 * Read-only resolver: workspace + module + task metadata → concrete delivery instructions.
 */
export function resolveMaintainerDeliveryPolicy(input) {
    const warnings = [];
    const explain = [];
    const cfg = parseMaintainerDeliveryPolicyConfig(input.effectiveConfig);
    const task = input.task ?? undefined;
    const taskId = (typeof input.taskId === "string" && input.taskId.trim().length > 0 ? input.taskId.trim() : null) ??
        task?.id ??
        null;
    const phaseKeyRaw = (typeof input.phaseKey === "string" && input.phaseKey.trim().length > 0
        ? input.phaseKey.trim()
        : null) ?? (task ? inferTaskPhaseKey(task) : null);
    const moduleId = typeof input.moduleId === "string" && input.moduleId.trim().length > 0
        ? input.moduleId.trim()
        : null;
    const slug = (typeof input.slug === "string" && input.slug.trim().length > 0
        ? input.slug.trim()
        : null) ?? (task ? slugifyTaskTitle(task.title) : null);
    const version = typeof input.version === "string" && input.version.trim().length > 0 ? input.version.trim() : "";
    const metaProfileRaw = task?.metadata && typeof task.metadata[MAINTAINER_DELIVERY_PROFILE_METADATA_KEY] === "string"
        ? String(task.metadata[MAINTAINER_DELIVERY_PROFILE_METADATA_KEY]).trim()
        : null;
    const moduleOverride = moduleId ? cfg.moduleOverrides[moduleId] : undefined;
    let profileName = cfg.defaultProfile;
    let profileSource = "workspace-default";
    if (metaProfileRaw && cfg.profiles[metaProfileRaw]) {
        profileName = metaProfileRaw;
        profileSource = "task-metadata";
    }
    else if (metaProfileRaw && !cfg.profiles[metaProfileRaw]) {
        warnings.push({
            code: "unknown-task-metadata-profile",
            message: `metadata.${MAINTAINER_DELIVERY_PROFILE_METADATA_KEY} '${metaProfileRaw}' is not defined in maintainerDelivery.profiles — falling back to workspace default`
        });
    }
    if (profileSource !== "task-metadata" && moduleOverride?.profile && cfg.profiles[moduleOverride.profile]) {
        profileName = moduleOverride.profile;
        profileSource = "module-override";
    }
    if (!cfg.profiles[profileName]) {
        profileName = "github-pr";
        profileSource = "built-in-default";
        warnings.push({
            code: "unknown-effective-profile",
            message: `Resolved profile missing from config — using built-in 'github-pr'`
        });
    }
    const rawProf = cfg.profiles[profileName];
    const profile = normalizeProfileRecord(rawProf);
    explain.push({ key: "profileName", value: profileName, source: profileSource });
    let maintainerDeliveryEnforcementMode = cfg.enforcementMode;
    explain.push({
        key: "maintainerDelivery.enforcementMode",
        value: maintainerDeliveryEnforcementMode,
        source: "workspace-default"
    });
    if (moduleOverride?.enforcementMode) {
        maintainerDeliveryEnforcementMode = moduleOverride.enforcementMode;
        explain.push({
            key: "maintainerDelivery.enforcementMode",
            value: maintainerDeliveryEnforcementMode,
            source: "module-override"
        });
    }
    const metaRequires = task?.metadata && task.metadata[REQUIRES_PHASE_BRANCH_METADATA_KEY] === true ? true : false;
    const metaRequiresFalse = task?.metadata && task.metadata[REQUIRES_PHASE_BRANCH_METADATA_KEY] === false ? true : false;
    let requiresPhaseBranch = profile.requiresPhaseBranch;
    let requiresSource = profileSource === "task-metadata"
        ? "workspace-default"
        : profileSource === "module-override"
            ? "module-override"
            : "workspace-default";
    if (metaRequires) {
        requiresPhaseBranch = true;
        requiresSource = "task-metadata";
    }
    if (metaRequiresFalse && profile.requiresPhaseBranch) {
        warnings.push({
            code: "requires-phase-branch-conflict",
            message: "metadata.requiresPhaseBranch is false but the resolved delivery profile expects a phase integration branch — metadata does not downgrade profile.requiresPhaseBranch"
        });
        explain.push({
            key: "requiresPhaseBranchConflict",
            value: true,
            source: "task-metadata"
        });
    }
    explain.push({ key: "requiresPhaseBranch", value: requiresPhaseBranch, source: requiresSource });
    const tokenCtx = {
        taskId: taskId ?? "",
        slug: slug ?? "",
        phaseKey: phaseKeyRaw ?? "",
        moduleId: moduleId ?? "",
        version
    };
    const phaseBranchPattern = profile.branchPattern;
    const phaseIntegrationBranch = phaseKeyRaw && phaseBranchPattern.includes("{phaseKey}")
        ? expandTokens(phaseBranchPattern, tokenCtx)
        : null;
    const taskBranchPattern = profile.taskBranchPattern ?? DEFAULT_MAINTAINER_DELIVERY_POLICY.profiles["github-pr"].taskBranchPattern;
    const taskBranchExample = taskId && slug && phaseKeyRaw
        ? expandTokens(taskBranchPattern, tokenCtx)
        : taskId && slug
            ? expandTokens(taskBranchPattern, tokenCtx)
            : null;
    const releaseTagPattern = profile.releaseTagPattern ?? null;
    const releaseTagExample = releaseTagPattern && version ? expandTokens(releaseTagPattern, tokenCtx) : null;
    explain.push({ key: "phaseBranchPattern", value: phaseBranchPattern, source: "workspace-default" });
    explain.push({ key: "taskBranchPattern", value: taskBranchPattern, source: "workspace-default" });
    if (releaseTagPattern) {
        explain.push({ key: "releaseTagPattern", value: releaseTagPattern, source: "workspace-default" });
    }
    const deliveryEvidenceEnforcementMode = readDeliveryEvidenceEnforcementMode(input.effectiveConfig);
    explain.push({
        key: "tasks.deliveryEvidence.enforcementMode",
        value: deliveryEvidenceEnforcementMode,
        source: "workspace-default"
    });
    const resolvedPolicy = {
        schemaVersion: 1,
        profileName,
        maintainerDeliveryEnforcementMode,
        deliveryEvidenceEnforcementMode,
        requiresPhaseBranch,
        phaseBranchPattern,
        phaseIntegrationBranch,
        taskBranchPattern,
        taskBranchExample,
        releaseTagPattern,
        releaseTagExample,
        reviewMode: profile.review,
        evidenceMode: profile.evidenceKind,
        prProvider: profile.prProvider ?? "github",
        mergeStrategy: profile.mergeStrategy ?? "merge",
        phaseToMainMode: profile.phaseToMainMode ?? "phase-closeout",
        mergeTarget: {
            kind: "phase-integration-branch",
            pattern: phaseBranchPattern,
            branch: phaseIntegrationBranch
        },
        playbookPath: ".ai/playbooks/task-to-phase-branch.md",
        playbookCursorRulePath: ".cursor/rules/playbook-task-to-phase-branch.mdc",
        machinePlaybooksPath: ".ai/MACHINE-PLAYBOOKS.md"
    };
    return {
        resolvedPolicy,
        explain,
        warnings,
        precedenceOrder: [...TASK_POLICY_OVERRIDE_PRECEDENCE]
    };
}
