/**
 * Sanity Canvas adapter — config schema + eager-validating helper.
 *
 * `defineCanvasSource` is the user-facing entry point for declaring a
 * Canvas source in `config/sources.ts`. It parses the input through Zod
 * eagerly so typos / wrong shapes surface at config-load time, not at
 * first eval-run. As a convenience, `documentIds` entries may be dashboard
 * doc URLs — they are normalized to bare ids and validated against the
 * declared environment + organization before the schema parse.
 */
import { z } from "zod";
import { DEFAULT_CANVAS_TOKEN_ENV_VAR } from "./auth.js";
import { canvasHosts, DASHBOARD_DOC_PATH } from "./hosts.js";
import { CANVAS_ID_PATTERN } from "./ids.js";
/**
 * Zod schema for a Canvas source. Asserts `satisfies z.ZodType<CanvasSource>`
 * against the independently-authored interface in `types.ts` (D0045 trust-
 * boundary rule) — drift becomes a compile error.
 */
export const CanvasSourceSchema = z.object({
    kind: z.literal("sanity-canvas").default("sanity-canvas"),
    name: z.string().min(1, "name is required"),
    environment: z.enum(["production", "staging"]),
    organizationId: z.string().min(1, "organizationId is required"),
    // Canvas ids are alphanumeric + `_-`; the regex also guards the URL-path
    // interpolation seam in `canvas-client.ts` (`…/documents/<id>`).
    resourceId: z
        .string()
        .regex(CANVAS_ID_PATTERN, "resourceId must match /^[A-Za-z0-9_-]+$/"),
    documentIds: z
        .array(z
        .string()
        .regex(CANVAS_ID_PATTERN, "documentId must match /^[A-Za-z0-9_-]+$/"))
        .min(1, "a canvas source needs at least one document id"),
    tokenEnvVar: z.string().min(1).default(DEFAULT_CANVAS_TOKEN_ENV_VAR),
    default: z.boolean().optional(),
});
/**
 * Define a Sanity Canvas doc source for `config/sources.ts`. Validates
 * eagerly; throws a `ZodError` (or a descriptive `Error` for URL-form
 * document entries) on bad input. The returned value is fully populated
 * with defaults (`kind`, `tokenEnvVar`); `environment` is deliberately
 * required — see the {@link CanvasSource} deployment-status note.
 *
 * `documentIds` entries may be dashboard doc URLs
 * (`https://<dashboard host>/@<org>/canvas/doc/<id>`) — the id is
 * extracted, and the URL's host and org must agree with the declared
 * `environment` / `organizationId` so a pasted wrong-environment link
 * fails at config time instead of as a mid-run 404.
 */
export function defineCanvasSource(input) {
    // Non-array documentIds falls through to the schema so the author gets a
    // ZodError naming the field, not a raw TypeError from .map.
    const documentIds = Array.isArray(input.documentIds)
        ? input.documentIds.map((entry) => normalizeDocumentEntry(entry, input))
        : input.documentIds;
    return CanvasSourceSchema.parse({ ...input, documentIds });
}
/**
 * Project a Canvas source onto the resolved-source shape, so `loadSource`
 * can return a plain `ResolvedSourceConfig` for Canvas too — keeping Canvas
 * contained here and sparing every downstream step a source-kind branch
 * (mirrors `resolveGoogleDriveSource`).
 *
 * The dashboard org canvas home surfaces as `baseUrl` so logs and
 * provenance name the real source. Sanity-only coordinates stay empty —
 * the fetch runs through the Canvas preset, not these fields. No llms.txt:
 * Canvas has no site index; docs are read directly through this adapter.
 */
export function resolveCanvasSource(source) {
    const hosts = canvasHosts(source);
    return {
        baseUrl: `${hosts.dashboard}/@${source.organizationId}/canvas`,
        dataset: "",
        documentIds: [],
        llmsTxt: "",
        name: source.name,
        priorityDomain: new URL(hosts.dashboard).host,
        projectId: "",
        studioOrigin: "",
        urls: [],
    };
}
/**
 * Accept a bare document id as-is; extract + validate the id from a
 * dashboard doc URL. URL entries must belong to the declared environment
 * and organization — a mismatch is a config error, named on both sides.
 */
function normalizeDocumentEntry(entry, input) {
    if (!entry.includes("://")) {
        return entry;
    }
    let url;
    try {
        url = new URL(entry);
    }
    catch {
        throw new Error(`defineCanvasSource: document entry ${JSON.stringify(entry)} is neither a Canvas document id nor a URL`);
    }
    const match = DASHBOARD_DOC_PATH.exec(url.pathname);
    if (!match) {
        throw new Error(`defineCanvasSource: ${JSON.stringify(entry)} is not a Canvas doc URL (expected <dashboard host>/@<org>/canvas/doc/<id>)`);
    }
    const [, org, documentId] = match;
    const expectedHost = new URL(canvasHosts(input).dashboard).host;
    if (url.host !== expectedHost) {
        throw new Error(`defineCanvasSource: ${JSON.stringify(entry)} points at ${url.host}, but environment "${input.environment}" expects ${expectedHost} — wrong environment for this source`);
    }
    if (org !== input.organizationId) {
        throw new Error(`defineCanvasSource: ${JSON.stringify(entry)} belongs to org @${org}, but this source declares organizationId "${input.organizationId}"`);
    }
    return documentId;
}
