import { z } from 'zod';
import { zodToJsonSchema } from 'zod-to-json-schema';
/**
 * Ordered pipeline stages. Index position determines progression — used to
 * skip completed stages when a build is retried after a worker crash.
 * 'ready' is included as the final stage; 'error' is terminal but not a
 * stage (not reachable through normal progression).
 */
export const APP_VERSION_STAGE_ORDER = [
    'pending',
    'sandbox',
    'catalog',
    'generating',
    'building',
    'packaging',
    'ready',
];
export const APP_VERSION_TERMINAL_STATUSES = ['ready', 'error'];
/**
 * Error message stamped on a version when the user cancels its build. There is
 * no dedicated 'cancelled' status — cancellation is an 'error' carrying this
 * marker, which the pipeline also reads to detect that a previous prompt was
 * cancelled mid-generation.
 */
export const APP_VERSION_CANCELLED_BY_USER = 'Cancelled by user';
export const isAppVersionInProgress = (status) => !APP_VERSION_TERMINAL_STATUSES.includes(status);
/**
 * Data apps are created with an empty name and only get an auto-generated
 * title after their first version builds successfully. If that build never
 * completes the name stays blank. Everywhere an app name is shown to the user,
 * fall back to a stable, identifiable placeholder instead of rendering nothing
 * — the uuid suffix keeps two unnamed apps distinguishable. Use this as the
 * single source of truth so the convention stays consistent across the UI.
 */
export const getAppDisplayName = (name, appUuid) => name.trim().length > 0 ? name : `Untitled app ${appUuid.slice(0, 8)}`;
/** Starter template for a single-tile renderer that emits a typed viz schema. */
export const DATA_APP_VIZ_TEMPLATE = 'data_app_viz';
export const DATA_APP_TEMPLATES = [
    'dashboard',
    'slideshow',
    'pdf',
    'custom',
    DATA_APP_VIZ_TEMPLATE,
];
/**
 * Claude model used to generate / iterate the data app inside the sandbox.
 * Mapped to the Claude CLI's `--model <alias>` flag verbatim. Persisted
 * per-version on `AppVersionResources.claudeModel` so the user can switch
 * mid-iteration without losing the record of which model built which version.
 */
export const DATA_APP_CLAUDE_MODELS = ['opus', 'sonnet', 'haiku'];
export const DEFAULT_DATA_APP_CLAUDE_MODEL = 'sonnet';
/**
 * Fold clarifications into the prompt sent to the sandbox. The persisted
 * prompt stays as the user's original words — clarifications travel
 * separately on `resources.clarifications` for chat rendering.
 */
export const formatPromptWithClarifications = (prompt, clarifications) => {
    if (!clarifications || clarifications.length === 0)
        return prompt;
    const qa = clarifications
        .map((c, i) => `${i + 1}. Q: ${c.question.trim()}\n   A: ${c.answer.trim()}`)
        .join('\n');
    return `${prompt}\n\nClarifications:\n${qa}`;
};
const uniqueNames = (arr) => new Set(arr.map((a) => a.name)).size === arr.length;
const optionBase = {
    name: z.string().min(1),
    label: z.string(),
    group: z.string().optional(),
};
// Runtime validator for the untrusted generated declaration. Also the source
// for the JSON Schema embedded in the generation prompt.
export const dataAppVizSchema = z.object({
    fields: z
        .array(z.object({
        name: z.string().min(1),
        label: z.string(),
        type: z.enum(['dimension', 'metric', 'series']),
        required: z.boolean(),
    }))
        .refine(uniqueNames, 'duplicate field name'),
    configOptions: z
        .array(z.discriminatedUnion('type', [
        z.object({
            ...optionBase,
            type: z.literal('boolean'),
            default: z.boolean(),
        }),
        z.object({
            ...optionBase,
            type: z.literal('select'),
            choices: z
                .array(z.object({ value: z.string(), label: z.string() }))
                .min(1),
            default: z.string(),
        }),
        z.object({
            ...optionBase,
            type: z.literal('number'),
            default: z.number(),
            min: z.number().optional(),
            max: z.number().optional(),
        }),
        z.object({
            ...optionBase,
            type: z.literal('text'),
            default: z.string(),
        }),
        z.object({
            ...optionBase,
            type: z.literal('color'),
            default: z.string(),
        }),
        z.object({
            ...optionBase,
            type: z.literal('palette'),
            default: z.array(z.string()),
        }),
    ]))
        .default([])
        .refine(uniqueNames, 'duplicate option name'),
});
const dataAppVizSchemaMatchesApiType = true;
void dataAppVizSchemaMatchesApiType;
// JSON Schema form of `dataAppVizSchema` for the generator CLI's `--json-schema`
// flag. Refinements (e.g. unique names) don't survive the conversion and stay
// enforced by the runtime `safeParse`.
export const dataAppVizJsonSchema = zodToJsonSchema(dataAppVizSchema);
/** Effective option values = stored value ?? declared default (derive, never seed). */
export const getEffectiveOptionValues = (configOptions, optionValues) => Object.fromEntries(configOptions.map((o) => [o.name, optionValues[o.name] ?? o.default]));
// postMessage type the host uses to push render context into the sandboxed
// iframe over the existing app SDK bridge (no new transport).
export const APP_SDK_DATA_APP_VIZ_CONTEXT_MESSAGE = 'lightdash:sdk:data-app-viz-context';
// postMessage type the iframe posts on mount (via the SDK's useVizContext) to
// ask the host to push the current context — the renderer may mount after the
// host's first push, so this handshake replaces blind timed re-sends.
export const APP_SDK_VIZ_CONTEXT_REQUEST_MESSAGE = 'lightdash:sdk:viz-context-request';
//# sourceMappingURL=types.js.map