import { ProductScope, ProductDefinition, ProductNavLink } from '../product-registry.js';
import { CustomProductBrand } from '../custom-product-defaults.js';
import 'react';
import '../../app-store-mJIbpFxa.js';
import 'zustand/middleware';
import 'zustand';
import '../product-brand.js';

/**
 * Tenant product store — serializable shapes for permanent browser-local
 * persistence (survives Cloudflare deploys; cleared only on explicit delete).
 */

declare const TENANT_STORE_KEY = "tenant-store:v1";
declare const TENANT_STORE_VERSION = 1;
declare const TENANT_PRODUCT_DATA_VERSION = 1;
/** Nav row storable in localStorage (icons as FA class strings). */
interface SerializableNavLink {
    key: string;
    title: string;
    url: string;
    iconClass: string;
    iconActiveClass?: string;
    badge?: number | string;
    secondaryPanel?: string;
    primaryHubChildKey?: string;
    children?: SerializableNavLink[];
}
/**
 * Full product definition persisted for Settings and `defineProduct` parity.
 * `source: "user"` — created/edited in Settings. `source: "code"` — seeded from
 * `registerProducts()` at bootstrap (user edits on user fields are preserved).
 */
interface TenantProductRecord {
    id: string;
    slug: string;
    label: string;
    brandPrefix: string;
    brandSuffix: string;
    brandColor: string;
    scope: ProductScope;
    nav: SerializableNavLink[];
    defaultPath: string;
    source: "user" | "code";
    createdAt: string;
    updatedAt: string;
    /** Soft-delete — hidden from switcher until purged. */
    deletedAt?: string | null;
    /** Forward-compatible bag for future DS capabilities. */
    extensions?: Record<string, unknown>;
}
/**
 * Per-product data document — all domain + hub payloads for one product.
 * Prefer writing new capabilities under `extensions` or typed sections below.
 */
interface TenantProductDataBag {
    v: number;
    /** Hub/table/page persisted slices (structured by consumer). */
    hubs: Record<string, unknown>;
    /** Entity collections (library items, placements, …). */
    entities: Record<string, unknown>;
    /** Product-level preferences not tied to a hub. */
    preferences: Record<string, unknown>;
    /**
     * Raw legacy `exxat-ds:<slug>:…` values imported during migration so nothing
     * is lost when upgrading from pre–tenant-store packages.
     */
    legacy: Record<string, string>;
    /** Open-ended capability storage. */
    extensions: Record<string, unknown>;
}
interface TenantStoreMeta {
    migratedFromCustomProducts?: boolean;
    migratedLegacyStorageKeys?: boolean;
    lastMigrationAt?: string;
}
interface TenantStore {
    v: number;
    catalog: TenantProductRecord[];
    products: Record<string, TenantProductDataBag>;
    /** `customProducts[i]` → `catalog[].id` after migration from app-store v9. */
    legacyCustomIndexMap?: string[];
    meta: TenantStoreMeta;
}
declare function emptyProductDataBag(): TenantProductDataBag;
declare function emptyTenantStore(): TenantStore;

/**
 * Default nav + metadata for tenant products created from Settings
 * (Prism-equivalent IA under `/<slug>/…`).
 */

/** Hub segments provisioned under `/:slug/<segment>/*` in the generic shell. */
declare const TENANT_PRODUCT_SHELL_HUBS: readonly [{
    readonly key: "library";
    readonly title: "Library";
    readonly segment: "library";
    readonly iconClass: "fa-light fa-books";
    readonly iconActiveClass: "fa-solid fa-books";
    readonly secondaryPanel: "library";
}, {
    readonly key: "placements";
    readonly title: "Placements";
    readonly segment: "placements";
    readonly iconClass: "fa-light fa-location-dot";
    readonly iconActiveClass: "fa-solid fa-location-dot";
}, {
    readonly key: "team";
    readonly title: "Team";
    readonly segment: "team";
    readonly iconClass: "fa-light fa-users";
    readonly iconActiveClass: "fa-solid fa-users";
}, {
    readonly key: "compliance";
    readonly title: "Compliance";
    readonly segment: "compliance";
    readonly iconClass: "fa-light fa-shield-check";
    readonly iconActiveClass: "fa-solid fa-shield-check";
}];
type TenantProductShellHubKey = (typeof TENANT_PRODUCT_SHELL_HUBS)[number]["key"];
/** Route segments for generic product shell (excludes dashboard). */
declare const TENANT_PRODUCT_SHELL_HUB_SEGMENTS: ("library" | "placements" | "team" | "compliance")[];
/** Build Prism-shaped sidebar links for a tenant product slug. */
declare function defaultTenantNavForSlug(slug: string): SerializableNavLink[];
declare const DEFAULT_TENANT_BRAND_PREFIX = "Exxat";

/**
 * Load / save the unified tenant product store (`exxat-ds:tenant-store:v1`).
 */

declare function loadTenantStore(): TenantStore;
declare function saveTenantStore(store: TenantStore): void;
declare function getActiveCatalog(store: TenantStore): TenantProductRecord[];
declare function getTenantProductById(store: TenantStore, id: string): TenantProductRecord | undefined;
declare function getTenantProductBySlug(store: TenantStore, slug: string): TenantProductRecord | undefined;
/** Mirror for legacy `customProducts[]` + routing helpers. */
declare function catalogToCustomProducts(catalog: TenantProductRecord[]): CustomProductBrand[];
/** Settings / switcher mirror — user-created products only (not `registerProducts` code seeds). */
declare function userCatalogToCustomProducts(catalog: TenantProductRecord[]): CustomProductBrand[];
declare function listLegacyStorageKeysForSlug(slug: string): string[];
/** Relative path inside `exxat-ds:` (e.g. `assessment:library:lifecycle:v1:main`). */
declare function legacyKeyToRelativePath(fullKey: string): string;

/**
 * Convert between persisted tenant records and runtime {@link ProductDefinition}.
 */

declare function serializableNavToRuntime(links: SerializableNavLink[]): ProductNavLink[];
declare function tenantRecordToDefinition(record: TenantProductRecord): ProductDefinition;
declare function definitionToTenantRecord(def: ProductDefinition, source: "user" | "code", existing?: TenantProductRecord): TenantProductRecord;
declare function brandToTenantRecord(input: {
    suffix: string;
    brandColor: string;
    id?: string;
}): TenantProductRecord;

/**
 * Read / write arbitrary per-product data inside the tenant store.
 */

declare function getTenantProductData<T>(productId: string, path: string, defaultValue: T): T;
declare function setTenantProductData(productId: string, path: string, value: unknown, options?: {
    debounceMs?: number;
}): void;
/** Import a legacy `exxat-ds:` value into the product bag (idempotent). */
declare function importLegacyKeyIntoProduct(productId: string, relativeKey: string, rawValue: string): void;
declare function removeTenantProductData(productId: string): void;
declare function readTenantProductDataBag(productId: string): TenantProductDataBag | null;
/**
 * Dual-write helper: persist structured data AND keep legacy key for older
 * package versions until fully migrated.
 */
declare function setTenantProductDataWithLegacyMirror(productId: string, path: string, value: unknown, legacyStorageKey?: string): void;
declare function getTenantProductDataFromLegacyOrBag<T>(productId: string, path: string, legacyStorageKey: string | undefined, defaultValue: T): T;

/**
 * One-time migration: `customProducts[]` + legacy `exxat-ds:<slug>:*` keys →
 * unified tenant store. Safe to run on every hydration (idempotent).
 */

/**
 * Upsert every Settings row into the tenant catalog (idempotent by slug).
 * Runs on every hydration so `exxat-app` and `tenant-store:v1` stay aligned.
 */
declare function syncCustomProductsIntoCatalog(store: TenantStore, customProducts: CustomProductBrand[]): void;
interface TenantMigrationResult {
    store: TenantStore;
    /** Updated mirror for `useAppStore.customProducts`. */
    customProducts: CustomProductBrand[];
}
/**
 * Run all tenant-store migrations. Pass the hydrated `customProducts` array
 * from `useAppStore` so v9 installs upgrade without data loss.
 */
declare function runTenantProductMigration(customProducts: CustomProductBrand[]): TenantMigrationResult;
/** Remove a tenant product and its `exxat-ds:<slug>:*` legacy keys. */
declare function deleteTenantProductPermanently(productId: string): void;

/**
 * CRUD for tenant products — used by Settings and `registerProducts` merge.
 */

declare function listTenantProducts(): TenantProductRecord[];
declare function upsertUserTenantProductFromBrand(brand: CustomProductBrand): {
    index: number;
    record: TenantProductRecord;
};
declare function mergeCodeProductsIntoTenantStore(definitions: ProductDefinition[]): void;
declare function registerProductsFromTenantStore(): void;
declare function removeTenantProduct(productId: string): CustomProductBrand[];
declare function syncCustomProductsMirror(): CustomProductBrand[];

/**
 * Bootstrap hook — migrate legacy state, mirror `customProducts`, register
 * tenant catalog with the in-memory product registry.
 */

interface HydrateTenantProductsOptions {
    /** `customProducts` from hydrated `useAppStore`. */
    customProducts: CustomProductBrand[];
    /** Code-defined products from `registerProducts()` at app bootstrap. */
    codeProducts?: ProductDefinition[];
}
interface HydrateTenantProductsResult {
    customProducts: CustomProductBrand[];
}
/**
 * Call once after `useAppStore` rehydrates (e.g. in `ProductProvider`).
 * Idempotent — safe on every page load.
 */
declare function hydrateTenantProducts(options: HydrateTenantProductsOptions): HydrateTenantProductsResult;

/**
 * Deploy-time product catalog (`public/tenant-products.json`).
 *
 * Loaded on every app boot from the static host so products survive clear site
 * data and work for all visitors — same outcome as code-seeded products (test-10).
 */

declare const DEFAULT_SHIPPED_CATALOG_URL = "/tenant-products.json";
declare const SHIPPED_CATALOG_FILE_VERSION = 1;
/** Deploy-time slice of a product data bag (entities, hubs, preferences). */
interface ShippedProductDataSlice {
    entities?: Record<string, unknown>;
    hubs?: Record<string, unknown>;
    preferences?: Record<string, unknown>;
    /**
     * Raw `exxat-ds:<slug>:*` localStorage payloads (relative paths → values).
     * Restored on boot so hub filters / columns survive clear site data when
     * the builder syncs or deploys `tenant-products.json`.
     */
    storageSnapshot?: Record<string, string>;
}
interface ShippedTenantCatalogFile {
    v: typeof SHIPPED_CATALOG_FILE_VERSION;
    /** ISO timestamp when the file was exported (informational). */
    exportedAt?: string;
    catalog: TenantProductRecord[];
    /**
     * Per-product domain + hub payloads keyed by catalog `id`.
     * Merged on boot so `entities.*` survives clear site data when committed
     * to `public/tenant-products.json` and redeployed.
     */
    productData?: Record<string, ShippedProductDataSlice>;
}
declare function resetShippedCatalogBootstrapForTests(): void;
/** Resolves once {@link loadShippedTenantCatalog} has finished (success or 404). */
declare function ensureShippedCatalogLoaded(url?: string): Promise<void>;
/**
 * Fetch `tenant-products.json` from the deploy root and merge into the tenant
 * store + in-memory registry. Missing file is OK (404).
 */
declare function loadShippedTenantCatalog(url?: string): Promise<ShippedTenantCatalogFile | null>;
/** Shipped baseline merged under browser-local overlays (local wins on conflict). */
declare function mergeShippedProductDataIntoBag(bag: TenantProductDataBag, shipped?: ShippedProductDataSlice): TenantProductDataBag;
declare function mergeShippedCatalogIntoTenantStore(records: TenantProductRecord[], productData?: Record<string, ShippedProductDataSlice>): void;
declare function mergeShippedDefinitionsIntoTenantStore(definitions: ProductDefinition[]): void;
/** Build the JSON file customers commit under `public/tenant-products.json`. */
declare function buildShippedTenantCatalogFile(records?: TenantProductRecord[]): ShippedTenantCatalogFile;
/** Include hub `localStorage` snapshots (builder export / dev sync). */
declare function enrichShippedFileWithStorageSnapshots(file: ShippedTenantCatalogFile): ShippedTenantCatalogFile;
declare function buildBuilderShippedCatalogFile(): ShippedTenantCatalogFile;
declare function serializeShippedTenantCatalogFile(file: ShippedTenantCatalogFile): string;
/** Browser: download catalog for commit to `public/tenant-products.json`. */
declare function downloadShippedTenantCatalog(records?: TenantProductRecord[], filename?: string): void;
/** Append one Settings-created product to a deploy catalog export. */
declare function tenantRecordFromCustomBrand(suffix: string, brandColor: string): TenantProductRecord;

/**
 * Builder dev sync — auto-persist tenant catalog + hub localStorage to
 * `public/tenant-products.json` via the Vite dev plugin so builder work
 * survives hard refresh and **clear site data** during local `pnpm dev`.
 */

declare const BUILDER_DEV_SYNC_PATH = "/__exxat/builder-sync";
declare function isBuilderDevSyncEnvironment(): boolean;
/**
 * Start debounced auto-sync when builder authoring is enabled in dev.
 *
 * Writes are driven exclusively by `markBuilderStateDirty()` (real user
 * actions — Add product, edit entity, hub state changes) and a final
 * `beforeunload` flush. We deliberately do NOT schedule an unconditional
 * write at startup: hydrate of the tenant store from `tenant-products.json`
 * is wrapped in `runWithoutBuilderDevSync`, so there is nothing new to
 * persist on mount. A boot-time write would round-trip the same content
 * (with fresh `exportedAt` / per-record `updatedAt`) back to disk, which
 * Vite's watcher then reloads — creating the historical 3–5 Hz refresh
 * loop fixed in @exxatdesignux/ui@0.6.18.
 */
declare function startBuilderDevSync(): () => void;

/**
 * Scaffold files when a builder adds a product (Settings or CLI).
 * Customer commits generated output + `public/tenant-products.json`, then deploys.
 */

interface ProductCodegenFile {
    /** Repo-relative path */
    path: string;
    content: string;
}
interface ProductCodegenResult {
    slug: string;
    files: ProductCodegenFile[];
    instructions: string[];
}
declare function generateProductScaffold(record: TenantProductRecord): ProductCodegenResult;
declare function downloadProductScaffold(record: TenantProductRecord): void;

export { BUILDER_DEV_SYNC_PATH, DEFAULT_SHIPPED_CATALOG_URL, DEFAULT_TENANT_BRAND_PREFIX, type HydrateTenantProductsOptions, type HydrateTenantProductsResult, type ProductCodegenFile, type ProductCodegenResult, SHIPPED_CATALOG_FILE_VERSION, type SerializableNavLink, type ShippedProductDataSlice, type ShippedTenantCatalogFile, TENANT_PRODUCT_DATA_VERSION, TENANT_PRODUCT_SHELL_HUBS, TENANT_PRODUCT_SHELL_HUB_SEGMENTS, TENANT_STORE_KEY, TENANT_STORE_VERSION, type TenantMigrationResult, type TenantProductDataBag, type TenantProductRecord, type TenantProductShellHubKey, type TenantStore, type TenantStoreMeta, brandToTenantRecord, buildBuilderShippedCatalogFile, buildShippedTenantCatalogFile, catalogToCustomProducts, defaultTenantNavForSlug, definitionToTenantRecord, deleteTenantProductPermanently, downloadProductScaffold, downloadShippedTenantCatalog, emptyProductDataBag, emptyTenantStore, enrichShippedFileWithStorageSnapshots, ensureShippedCatalogLoaded, generateProductScaffold, getActiveCatalog, getTenantProductById, getTenantProductBySlug, getTenantProductData, getTenantProductDataFromLegacyOrBag, hydrateTenantProducts, importLegacyKeyIntoProduct, isBuilderDevSyncEnvironment, legacyKeyToRelativePath, listLegacyStorageKeysForSlug, listTenantProducts, loadShippedTenantCatalog, loadTenantStore, mergeCodeProductsIntoTenantStore, mergeShippedCatalogIntoTenantStore, mergeShippedDefinitionsIntoTenantStore, mergeShippedProductDataIntoBag, readTenantProductDataBag, registerProductsFromTenantStore, removeTenantProduct, removeTenantProductData, resetShippedCatalogBootstrapForTests, runTenantProductMigration, saveTenantStore, serializableNavToRuntime, serializeShippedTenantCatalogFile, setTenantProductData, setTenantProductDataWithLegacyMirror, startBuilderDevSync, syncCustomProductsIntoCatalog, syncCustomProductsMirror, tenantRecordFromCustomBrand, tenantRecordToDefinition, upsertUserTenantProductFromBrand, userCatalogToCustomProducts };
