import type { Theme } from "@riverbankcms/blocks";
import type { ListMediaAssetsResult, MediaAssetWithLabels } from "@riverbankcms/media-storage-supabase";
import type { DbJson } from "@riverbankcms/db";
import type { PageDesignEditorReadModel, PageDesignIntent, AppearancePresetId, BoundaryOptionId, DesignBlockId, LayoutVariantKey } from "@riverbankcms/theme-core/site-styles";
import type { ButtonPersonalityId } from "@riverbankcms/theme-core/buttons";
import type { PaletteOverrides, PaletteVariantId } from "@riverbankcms/theme-core/palette";
/**
 * Round-trip shape for the Style configurator's persisted selections on the
 * `saveSiteTheme` endpoint. Each field is optional independently so callers
 * can update one decision at a time; `null` explicitly clears the selection
 * (server falls back to the site style's default), distinct from omission
 * which preserves the existing persisted value.
 */
export type SiteThemeSelectionsPayload = {
    buttonPersonalityId?: ButtonPersonalityId | null;
    paletteVariantId?: PaletteVariantId | null;
    paletteOverrides?: PaletteOverrides | null;
};
import type { APIEndpoint } from "./apiEndpointTypes";
import type { AnalyticsReportFilters, AnalyticsReportResponse } from "./analytics";
import type { CreateMediaAssetBody, MediaAssetResponse, MediaAssetFileFilterContract, MediaBulkDeleteResponse, MediaClassifyJobResponse, MediaJobSummaryResponse, MediaLabelSummary, MediaSettingsResponse } from "./media";
import type { MediaUsageCheckResponse } from "./shared-contracts";
import type { BlockWithContentResponse, BlockListItem, ContentEntryListStage, ListPublishedEntriesResponse, PageDraftRecord, PublishedBlockBaseline, PublishedContentEntryPreviewResponse, PublishedPostPreviewResponse, SdkBlockContent, SdkRuntimeContentByPathResponse, SdkTemplate, SiteBySlugResponse, ThemeGenerationTurn, ThemePreferencesRecord, ThemeRow } from "./contentRuntime";
import type { CreateInstagramZipUploadUrlRequest, CreateInstagramZipUploadUrlResponse, CreateMediaUploadUrlRequest, CreateMediaUploadUrlResponse, CreateSiteLogoUploadUrlRequest, CreateSiteLogoUploadUrlResponse, InstagramUploadZipRequest, MediaUploadFinalizeRequest, UploadSiteLogoRequest } from "./siteInfrastructure";
import type { DevToolsGetSiteRoleDowngradeQuery, DevToolsImpersonationResponse, DevToolsSeedResponse, DevToolsSetSiteRoleDowngradeRequest, SiteRoleDowngradeState } from "./siteOperations";
export type PageDesignRevisionToken = {
    kind: "absent";
} | {
    kind: "draft" | "published";
    contentVersionId: string;
    updatedAt: string;
};
export type SavePageDesignStateResponse = {
    ok: true;
    outcome: "created" | "updated";
    revision: PageDesignRevisionToken;
};
export type PageDesignEditorAction = {
    kind: "set-layout";
    blockId: DesignBlockId;
    layoutVariantKey: LayoutVariantKey;
    baseContentId: string | null;
} | {
    kind: "set-look";
    blockId: DesignBlockId;
    appearancePresetId: AppearancePresetId | null;
} | {
    kind: "set-boundary";
    previousBlockId: DesignBlockId;
    nextBlockId: DesignBlockId;
    boundaryOptionId: BoundaryOptionId | null;
};
export type ApplyPageDesignEditorActionResponse = {
    ok: true;
    action: PageDesignEditorAction;
    content: null | {
        blockId: DesignBlockId;
        contentId: string;
        version: number;
        data: DbJson;
        stage: "draft" | "published";
    };
    revision: PageDesignRevisionToken;
    editorModel: PageDesignEditorReadModel;
};
export type PageDesignEditorStateResponse = {
    kind: "absent";
    revision: PageDesignRevisionToken;
} | {
    kind: "invalid";
    source: "draft" | "published-fallback";
    revision: PageDesignRevisionToken;
    message: string;
} | {
    kind: "loaded";
    source: "draft" | "published-fallback";
    revision: PageDesignRevisionToken;
    editorModel: PageDesignEditorReadModel;
};
export type PageBlockDesignSyncWarning = Readonly<{
    kind: "blocked" | "failed" | "skipped-invalid";
    operation: "create" | "delete" | "reorder";
    message: string;
    blocker?: string;
    source?: "draft" | "published-fallback";
    reason?: string;
}>;
/**
 * Site runtime endpoints cover theme generation, site lookup, media/content runtime
 * APIs, lightweight dev-tools helpers, and client-side analytics collection that used
 * to live inline inside `types.ts`.
 */
export type SiteRuntimeAPIEndpoints = {
    getPublishedPostPreview: APIEndpoint<never, {
        siteId: string;
        slug: string;
    }, PublishedPostPreviewResponse>;
    getPublishedEntryPreview: APIEndpoint<never, {
        siteId: string;
        type: string;
        slug: string;
    }, PublishedContentEntryPreviewResponse>;
    listPublishedEntries: APIEndpoint<never, {
        siteId: string;
        type: string;
        limit?: string;
        offset?: string;
        order?: "published_at.asc" | "published_at.desc" | "title.asc" | "title.desc" | "updated_at.asc" | "updated_at.desc";
        stage?: ContentEntryListStage;
        meta?: string;
        mode?: "manual";
        entryIds?: string;
    }, ListPublishedEntriesResponse>;
    createTheme: APIEndpoint<{
        site_id: string;
    }, never, {
        output: ThemeGenerationTurn[];
        text: string[] | null;
    }>;
    generateThemes: APIEndpoint<{
        site_id: string;
    }, never, {
        themes: ThemeRow[];
    }>;
    extractThemeFromInspiration: APIEndpoint<{
        urls: string[];
    }, never, {
        palette: {
            primary: string;
            secondary: string;
            accent: string;
            background: string;
            surface: string;
            text: string;
        };
        mode: "light" | "dark";
        source: "extracted" | "fallback";
    }>;
    saveSiteTheme: APIEndpoint<{
        theme: Theme;
        themeId?: string | null;
        selectionId?: string | null;
        overrides?: Record<string, unknown> | null;
    } & SiteThemeSelectionsPayload, {
        siteId: string;
    }, {
        success: boolean;
        themeId: string;
        selectionId: string;
        savedAt: string;
        overrides: Record<string, unknown> | null;
        theme: Theme;
        /**
         * Persisted Style configurator selections. The client resolves
         * compatibility locally via `compileSiteThemeFromSelections` and sends
         * already-resolved IDs; this response echoes the row's stored state so
         * the caller can refresh local state without a follow-up read.
         */
        buttonPersonalityId: ButtonPersonalityId | null;
        paletteVariantId: PaletteVariantId | null;
        paletteOverrides: PaletteOverrides | null;
    }>;
    uploadSiteLogo: APIEndpoint<UploadSiteLogoRequest, never, {
        path: string;
        publicUrl: string | null;
        palette: string[];
    }>;
    createSiteLogoUploadUrl: APIEndpoint<CreateSiteLogoUploadUrlRequest, never, CreateSiteLogoUploadUrlResponse>;
    upsertThemePreferences: APIEndpoint<{
        site_id: string;
        has_brand_colors?: boolean;
        brand_colors?: string[];
        inspiration_urls?: string[];
        logo_path?: string | null;
        palette_variants?: Array<{
            key: string;
            recipe_id?: string;
            strategy?: "seedLocked" | "blendLocked";
            palette: {
                primary: string;
                secondary: string;
                accent: string;
                background: string;
                surface: string;
                text: string;
            };
        }>;
        selected_palette_key?: string;
        style_axes?: {
            energy?: "calm" | "vibrant";
            density?: "airy" | "compact";
        };
    }, never, {
        preferences: ThemePreferencesRecord;
    }>;
    getSite: APIEndpoint<never, // GET requests don't have body
    {
        id?: string;
        slug?: string;
        domain?: string;
        scope?: "full";
        currentPath?: string;
        force?: string;
    }, // Query parameters
    SiteBySlugResponse>;
    getSiteIdOnly: APIEndpoint<never, {
        id?: string;
        slug?: string;
        domain?: string;
        scope: "id-only";
    }, {
        site: {
            id: string;
        };
    }>;
    getSiteBySlug: APIEndpoint<never, // GET requests don't have body
    {
        slug: string;
    }, // Query parameters
    SiteBySlugResponse>;
    getSiteByDomain: APIEndpoint<never, // GET requests don't have body
    {
        domain: string;
    }, // Query parameters
    SiteBySlugResponse>;
    getSiteById: APIEndpoint<never, // GET requests don't have body
    {
        id: string;
    }, // Path parameters
    SiteBySlugResponse>;
    getBlockContent: APIEndpoint<never, // GET requests don't have body
    {
        blockId: string;
    }, // Path parameters
    BlockWithContentResponse>;
    instagramUploadZip: APIEndpoint<InstagramUploadZipRequest, undefined, {
        ok: boolean;
        imported: number;
        skipped: number;
        failed: number;
        totalPosts: number;
        errors: Array<{
            uri: string;
            error: string;
        }>;
    }>;
    createInstagramZipUploadUrl: APIEndpoint<CreateInstagramZipUploadUrlRequest, never, CreateInstagramZipUploadUrlResponse>;
    getAnalyticsReport: APIEndpoint<AnalyticsReportFilters, {
        siteId: string;
    } & AnalyticsReportFilters, AnalyticsReportResponse>;
    createMediaAsset: APIEndpoint<CreateMediaAssetBody, undefined, MediaAssetResponse>;
    mediaList: APIEndpoint<{
        siteId: string;
        q?: string;
        limit?: number;
        offset?: number;
        labels?: string;
        fileFilter?: MediaAssetFileFilterContract;
    }, never, ListMediaAssetsResult>;
    mediaProductFileList: APIEndpoint<{
        siteId: string;
        q?: string;
        limit?: number;
        offset?: number;
        labels?: string;
        fileFilter?: MediaAssetFileFilterContract;
    }, never, ListMediaAssetsResult>;
    mediaGet: APIEndpoint<never, {
        assetId: string;
    }, MediaAssetWithLabels>;
    mediaUpdate: APIEndpoint<{
        filename?: string;
        title?: string | null;
        altText?: string | null;
        caption?: string | null;
        width?: number | null;
        height?: number | null;
        durationSeconds?: number | null;
        thumbnailAssetId?: string | null;
        isThumbnail?: boolean;
    }, {
        assetId: string;
    }, MediaAssetWithLabels>;
    mediaCanonicalCrop: APIEndpoint<{
        rect: [number, number, number, number];
        rotation?: 0 | 90 | 180 | 270;
    }, {
        assetId: string;
    }, MediaAssetWithLabels>;
    mediaAssignIdentifier: APIEndpoint<never, {
        assetId: string;
    }, MediaAssetWithLabels>;
    mediaDelete: APIEndpoint<{
        deleteObject?: boolean;
        cascadeLabels?: boolean;
    }, {
        assetId: string;
    }, void>;
    mediaBulkDelete: APIEndpoint<{
        assetIds: string[];
        deleteObjects?: boolean;
        cascadeLabels?: boolean;
    }, never, MediaBulkDeleteResponse>;
    mediaUsageCheck: APIEndpoint<{
        assetIds: string[];
    }, never, MediaUsageCheckResponse>;
    mediaGetSignedUrl: APIEndpoint<never, {
        assetId: string;
        disposition?: "attachment" | "inline";
    }, {
        signedUrl: string;
    }>;
    createMediaUploadUrl: APIEndpoint<CreateMediaUploadUrlRequest, never, CreateMediaUploadUrlResponse>;
    mediaUpload: APIEndpoint<MediaUploadFinalizeRequest, undefined, MediaAssetWithLabels>;
    updateBlockContent: APIEndpoint<{
        path: string;
        value: DbJson;
        optimistic_hash?: string | null;
    }, {
        blockId: string;
    }, {
        ok: boolean;
        contentId: string;
        version: number;
        data: DbJson;
        stage: "draft" | "published";
        optimistic_hash?: string | null;
    }>;
    saveBlockContent: APIEndpoint<{
        data: DbJson;
        optimistic_hash?: string | null;
    } | {
        path: string;
        value: DbJson;
        optimistic_hash?: string | null;
    } | Record<string, unknown>, {
        blockId: string;
    }, {
        ok: boolean;
        contentId: string;
        version: number;
        data: DbJson;
        stage: "draft" | "published";
        optimistic_hash?: string | null;
    }>;
    createBlock: APIEndpoint<{
        kind: string;
        position?: number;
        purpose?: string;
        duplicatedFromBlockId?: string;
    }, {
        siteId: string;
        pageId: string;
    }, {
        ok: boolean;
        block: Record<string, unknown>;
        designSyncWarning?: PageBlockDesignSyncWarning;
    }>;
    reorderBlocks: APIEndpoint<{
        blockIds: string[];
    }, {
        siteId: string;
        pageId: string;
    }, {
        ok: boolean;
        designSyncWarning?: PageBlockDesignSyncWarning;
    }>;
    deleteBlock: APIEndpoint<never, {
        siteId: string;
        pageId: string;
        blockId: string;
    }, {
        ok: boolean;
        designSyncWarning?: PageBlockDesignSyncWarning;
    }>;
    listBlocks: APIEndpoint<never, {
        siteId: string;
        pageId: string;
    }, {
        blocks: BlockListItem[];
    }>;
    getPageById: APIEndpoint<never, {
        siteId: string;
        pageId: string;
    }, {
        page: {
            id: string;
            purpose: string;
            createdAt: string;
            updatedAt: string;
            name: string;
            path: string | null;
            status: string;
            draftStatus: string | null;
            publishedAt: string | null;
            draftUpdatedAt: string | null;
            draftTitle: string | null;
            draftPath: string | null;
            draftMetaTitle: string | null;
            draftMetaDescription: string | null;
            publishedMetaTitle: string | null;
            publishedMetaDescription: string | null;
            ogImageId: string | null;
            ogImageUrl: string | null;
            canonicalUrl: string | null;
            routeId: string | null;
            blocks: SdkBlockContent[];
        };
        templates?: SdkTemplate[];
    }>;
    publishPageDraft: APIEndpoint<never, {
        siteId: string;
        pageId: string;
    }, {
        page: PageDraftRecord;
        publishedBlocks?: PublishedBlockBaseline[];
    }>;
    discardPageDraft: APIEndpoint<never, {
        siteId: string;
        pageId: string;
    }, {
        page: PageDraftRecord;
    }>;
    getPageDesignEditorState: APIEndpoint<never, {
        siteId: string;
        pageId: string;
    }, PageDesignEditorStateResponse>;
    savePageDesignState: APIEndpoint<{
        designState: PageDesignIntent;
        expectedRevision: PageDesignRevisionToken;
    }, {
        siteId: string;
        pageId: string;
    }, SavePageDesignStateResponse>;
    applyPageDesignEditorAction: APIEndpoint<{
        action: PageDesignEditorAction;
    }, {
        siteId: string;
        pageId: string;
    }, ApplyPageDesignEditorActionResponse>;
    getContentByPath: APIEndpoint<{
        path: string;
        preview?: boolean;
    }, {
        siteId: string;
    }, SdkRuntimeContentByPathResponse>;
    getPageByPath: APIEndpoint<{
        path: string;
        preview?: boolean;
    }, {
        siteId: string;
    }, SdkRuntimeContentByPathResponse>;
    initSiteContent: APIEndpoint<{}, {
        siteId: string;
    }, {
        ok: boolean;
        created: number;
        totalBlocks: number;
    }>;
    getMediaLabels: APIEndpoint<{
        siteId: string;
    }, never, {
        items: MediaLabelSummary[];
    }>;
    getMediaSettings: APIEndpoint<never, {
        siteId: string;
    }, MediaSettingsResponse>;
    updateMediaSettings: APIEndpoint<{
        siteId: string;
        persistVariants: boolean;
    }, never, MediaSettingsResponse>;
    mediaSearch: APIEndpoint<{
        siteId: string;
        query: string;
        limit?: number;
        threshold?: number;
        labels?: string[];
    }, never, ListMediaAssetsResult>;
    classifyMediaAsset: APIEndpoint<{
        force?: boolean;
        prompt?: string;
    }, {
        assetId: string;
    }, {
        ok: boolean;
        job: MediaClassifyJobResponse | null;
        summary?: MediaJobSummaryResponse;
        reason?: string;
    }>;
    classifyMediaBatch: APIEndpoint<{
        siteId: string;
        assetIds?: string[];
        limit?: number;
        force?: boolean;
        prompt?: string;
    }, never, {
        ok: boolean;
        job: MediaClassifyJobResponse | null;
        summary: MediaJobSummaryResponse;
    }>;
    enqueueMediaClassifyJob: APIEndpoint<{
        siteId: string;
        assetIds?: string[];
        limit?: number;
        force?: boolean;
        prompt?: string;
    }, never, {
        kind: "noop";
        reason: string;
    } | {
        kind: "enqueued";
        job: MediaClassifyJobResponse;
    }>;
    runMediaClassifyJob: APIEndpoint<{
        siteId: string;
        jobId?: string;
        maxSteps?: number;
    }, never, {
        kind: "noop";
        reason: string;
    } | {
        kind: "ran";
        job: MediaClassifyJobResponse | null;
        summary?: MediaJobSummaryResponse;
        completed?: boolean;
    }>;
    runAllMediaClassifyJobs: APIEndpoint<{
        siteIds?: string[];
        maxSites?: number;
        maxSteps?: number;
    }, never, {
        ok: boolean;
        results: Array<{
            siteId: string;
            jobId: string | null;
            status: "skipped" | "completed" | "processing";
            summary?: MediaJobSummaryResponse;
        }>;
    }>;
    mediaJobsStatus: APIEndpoint<{
        siteId: string;
        limit?: number;
        statuses?: string;
    }, never, {
        jobs: MediaClassifyJobResponse[];
    }>;
    devToolsImpersonateAdmin: APIEndpoint<undefined, never, DevToolsImpersonationResponse>;
    devToolsImpersonateRandom: APIEndpoint<undefined, never, DevToolsImpersonationResponse>;
    devToolsGetSiteRoleDowngrade: APIEndpoint<never, DevToolsGetSiteRoleDowngradeQuery, SiteRoleDowngradeState>;
    devToolsSetSiteRoleDowngrade: APIEndpoint<DevToolsSetSiteRoleDowngradeRequest, never, SiteRoleDowngradeState>;
    devToolsSeedDemoData: APIEndpoint<undefined, never, DevToolsSeedResponse>;
    devToolsListOnboardingAttempts: APIEndpoint<undefined, {
        page?: string;
        limit?: string;
    }, {
        data: Array<{
            id: string;
            siteTitle: string;
            status: string;
            surfaceId: string;
            lastError: string | null;
            createdAt: string;
            updatedAt: string;
        }>;
        pagination: {
            page: number;
            limit: number;
            total: number;
        };
    }>;
    devToolsListOnboardingRuns: APIEndpoint<undefined, {
        attemptId: string;
        page?: string;
        limit?: string;
    }, {
        data: Array<{
            runId: string;
            runLabel: string | null;
            providerName: string;
            modelId: string;
            outcome: string;
            durationMs: number | null;
            siteId: string | null;
            siteSlug: string | null;
            previewUrl: string | null;
            createdAt: string;
        }>;
        pagination: {
            page: number;
            limit: number;
            total: number;
        };
    }>;
    devToolsTriggerOnboardingGeneration: APIEndpoint<{
        modelId: string;
    }, {
        attemptId: string;
    }, {
        success: boolean;
        runId: string;
        siteId: string | null;
        siteSlug: string | null;
        previewUrl: string | null;
        error: string | null;
        durationMs: number;
    }>;
    devToolsGetOnboardingRunDetails: APIEndpoint<undefined, {
        attemptId: string;
        runId: string;
    }, {
        data: Array<{
            source: string;
            pageTitle: string | null;
            stepId: string | null;
            attemptNumber: number;
            outcome: string;
            durationMs: number | null;
            validationIssues: string[] | null;
            message: string | null;
            errorMessage: string | null;
            createdAt: string;
        }>;
    }>;
    devToolsDeleteOnboardingRun: APIEndpoint<undefined, {
        attemptId: string;
        runId: string;
    }, {
        success: true;
    }>;
    devToolsRetryOnboardingRunStep: APIEndpoint<undefined, {
        attemptId: string;
        runId: string;
        stepId: string;
    }, {
        success: true;
        message: string;
    } | {
        success: false;
        error: string;
    }>;
    devToolsListOnboardingModels: APIEndpoint<undefined, never, {
        models: ReadonlyArray<{
            id: string;
            label: string;
            providerName: string;
            modelId: string;
        }>;
    }>;
    analyticsCollect: APIEndpoint<{
        siteId?: string;
        eventName: "page_view" | "cta_click" | "form_submit";
        path: string;
        referrer?: string | null;
        metadata?: Record<string, unknown>;
        sessionId?: string;
    }, never, void>;
};
