import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
import { useState, useEffect, useMemo, useCallback } from "react";
import { Button } from "../../../components/ui/button";
import { Input } from "../../../components/ui/input";
import { Select } from "../../../components/ui/select";
import { Dialog, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogTitle, } from "../../../components/ui/dialog";
import { setupWizardService, } from "../../../setup/services/setupWizardService";
import { AlertCircle, RefreshCw, Upload, Plus, ArrowRight, Brain, Image, Settings, Cloud, Trash2, Copy, } from "lucide-react";
import { useSearchParams } from "../../client/navigation";
import { AddModelDialog } from "../../../setup/wizard/steps/AddModelDialog";
import { ImportModelDialog } from "../../../setup/wizard/steps/ImportModelDialog";
import { Splitter } from "../../ui/Splitter";
import { ModelConfigPanel } from "./ModelConfigPanel";
import { useEditContext } from "../../client/editContext";
import { FilterInput } from "../../../components/FilterInput";
const SELECTED_MODEL_QUERY_PARAM = "modelId";
/**
 * True when a numeric price is present (including 0). Used for display and
 * "missing pricing" detection.
 */
const hasDefinedPricingValue = (value) => value !== undefined && value !== null;
const hasUsableImagePricing = (model) => hasDefinedPricingValue(model.pricing?.inputTextTokenCostPerMillion) ||
    hasDefinedPricingValue(model.pricing?.inputImageTokenCostPerMillion) ||
    hasDefinedPricingValue(model.pricing?.outputImageTokenCostPerMillion);
/**
 * True when the model row has nothing to show on the pricing line (no usable
 * token/image figures). This is the same condition used to decide whether to
 * show the warning — avoids blank rows when field-level "missing" logic drifts.
 */
const isPricingLineEmpty = (model) => !hasVisiblePricingSummary(model);
const getPricingWarningMessage = (model) => {
    const template = model.templateType || "Ai Chat Model";
    if (template === "Ai Image Model") {
        return "Pricing information is missing. Configure at least one image pricing field.";
    }
    if (template === "Ai Embeddings Model") {
        return "Pricing information is missing. Set Input Cost Per Million Tokens.";
    }
    const missingFields = [];
    if (!hasDefinedPricingValue(model.pricing?.inputCostPerMillionTokens)) {
        missingFields.push("Input Cost Per Million Tokens");
    }
    if (!hasDefinedPricingValue(model.pricing?.outputCostPerMillionTokens)) {
        missingFields.push("Output Cost Per Million Tokens");
    }
    if (missingFields.length === 0) {
        return "Pricing information is missing.";
    }
    return `Pricing information is missing. Set ${missingFields.join(" and ")}.`;
};
const hasVisiblePricingSummary = (model) => {
    if (!model.pricing) {
        return false;
    }
    if (model.templateType === "Ai Image Model") {
        return hasUsableImagePricing(model);
    }
    return (hasDefinedPricingValue(model.pricing.inputCostPerMillionTokens) ||
        hasDefinedPricingValue(model.pricing.outputCostPerMillionTokens) ||
        hasDefinedPricingValue(model.pricing.cachedInputCostPerMillionTokens));
};
/** Sitecore item name for lists and dialogs; falls back to API model id / key. */
function getModelListLabel(model) {
    return model.itemName?.trim() || model.name || model.key || "";
}
function normalizeModelId(id) {
    return (id || "").replace(/[{}]/g, "").toLowerCase();
}
function getModelTypeLabel(templateType) {
    switch (templateType) {
        case "Ai Chat Model":
            return "Chat";
        case "Ai Embeddings Model":
            return "Embeddings";
        case "Ai Image Model":
            return "Image";
        default:
            return templateType;
    }
}
/**
 * Settings panel for AI Models configuration.
 * Install and configure AI models for chat and other tasks.
 */
export function ModelsPanel() {
    const editContext = useEditContext();
    const searchParams = useSearchParams();
    const [state, setState] = useState("loading");
    const [installedModels, setInstalledModels] = useState([]);
    const [providers, setProviders] = useState([]);
    const [settingsExists, setSettingsExists] = useState(false);
    const [defaultChatModelId, setDefaultChatModelId] = useState("");
    const [defaultImageModelId, setDefaultImageModelId] = useState("");
    const [savingDefaults, setSavingDefaults] = useState(false);
    const [error, setError] = useState(null);
    const [updating, setUpdating] = useState(null);
    // Dialog states
    const [showAddDialog, setShowAddDialog] = useState(false);
    const [showImportDialog, setShowImportDialog] = useState(false);
    // URL-synced model selection
    const [urlSelectedModelId, setUrlSelectedModelId] = useState(searchParams.get(SELECTED_MODEL_QUERY_PARAM) ||
        (typeof window !== "undefined"
            ? new URLSearchParams(window.location.search).get(SELECTED_MODEL_QUERY_PARAM)
            : null));
    const [selectedModel, setSelectedModel] = useState(null);
    // Bulk pricing update state
    const [updatingAllPricing, setUpdatingAllPricing] = useState(false);
    // Delete state
    const [deleting, setDeleting] = useState(null);
    // Duplicate state
    const [duplicatingId, setDuplicatingId] = useState(null);
    const [duplicateDialogModel, setDuplicateDialogModel] = useState(null);
    const [duplicateItemName, setDuplicateItemName] = useState("");
    // Provider types (discovered from backend)
    const [providerTypes, setProviderTypes] = useState([]);
    // Filter state
    const [filterText, setFilterText] = useState("");
    useEffect(() => {
        const key = searchParams.get(SELECTED_MODEL_QUERY_PARAM) ||
            (typeof window !== "undefined"
                ? new URLSearchParams(window.location.search).get(SELECTED_MODEL_QUERY_PARAM)
                : null);
        setUrlSelectedModelId(key);
    }, [searchParams]);
    useEffect(() => {
        if (typeof window === "undefined")
            return;
        const handlePopState = () => {
            setUrlSelectedModelId(new URLSearchParams(window.location.search).get(SELECTED_MODEL_QUERY_PARAM));
        };
        window.addEventListener("popstate", handlePopState);
        return () => window.removeEventListener("popstate", handlePopState);
    }, []);
    useEffect(() => {
        if (!urlSelectedModelId) {
            if (selectedModel)
                setSelectedModel(null);
            return;
        }
        const match = installedModels.find((m) => m.id === urlSelectedModelId);
        if (match && match !== selectedModel) {
            setSelectedModel(match);
        }
    }, [installedModels, urlSelectedModelId, selectedModel]);
    const updateSelectedModelUrl = useCallback((modelId) => {
        editContext?.updateUrl({
            [SELECTED_MODEL_QUERY_PARAM]: modelId || undefined,
        });
        setUrlSelectedModelId(modelId || null);
    }, [editContext]);
    const handleOpenConfig = (model) => {
        setSelectedModel(model);
        updateSelectedModelUrl(model.id);
    };
    const handleCloseConfig = () => {
        setSelectedModel(null);
        updateSelectedModelUrl(null);
    };
    const loadData = async () => {
        try {
            setState("loading");
            setError(null);
            const [installed, providersData, providerTypesData, defaultModels, hasSettings,] = await Promise.all([
                setupWizardService.getInstalledModels(),
                setupWizardService.getProviders(),
                setupWizardService.getProviderTypes(),
                setupWizardService.getDefaultModels(),
                setupWizardService.getSettingsExists(),
            ]);
            setInstalledModels(installed);
            setProviders(providersData);
            setProviderTypes(providerTypesData);
            setSettingsExists(hasSettings);
            const resolvedChatModel = installed.find((model) => normalizeModelId(model.id) ===
                normalizeModelId(defaultModels.chatModelId));
            const resolvedImageModel = installed.find((model) => normalizeModelId(model.id) ===
                normalizeModelId(defaultModels.imageModelId));
            setDefaultChatModelId(resolvedChatModel?.id || defaultModels.chatModelId || "");
            setDefaultImageModelId(resolvedImageModel?.id || defaultModels.imageModelId || "");
            setState("success");
            return installed;
        }
        catch (e) {
            setState("error");
            setError(e?.message || "Failed to load models");
            return undefined;
        }
    };
    // Get providers that support model import (any provider with a registered provider type)
    const importableProviders = useMemo(() => {
        const providerTypeIds = new Set(providerTypes.map((p) => p.providerId));
        return providers.filter((p) => providerTypeIds.has(p.type));
    }, [providers, providerTypes]);
    // Get installed models that use importable providers (for pricing updates)
    const importableInstalledModels = useMemo(() => {
        const importableProviderIds = new Set(importableProviders.map((p) => p.id));
        return installedModels.filter((m) => m.providerId && importableProviderIds.has(m.providerId));
    }, [installedModels, importableProviders]);
    // Group installed models by provider for efficient batch updates
    const installedModelsByProvider = useMemo(() => {
        const groups = {};
        importableInstalledModels.forEach((model) => {
            if (model.providerId) {
                if (!groups[model.providerId]) {
                    groups[model.providerId] = [];
                }
                groups[model.providerId].push(model);
            }
        });
        return groups;
    }, [importableInstalledModels]);
    // Update pricing for all installed models from importable providers
    const handleUpdateAllPricing = async () => {
        if (importableInstalledModels.length === 0) {
            setError("No models with supported providers installed to update");
            return;
        }
        try {
            setUpdatingAllPricing(true);
            setError(null);
            let totalUpdated = 0;
            const allErrors = [];
            // Process each provider's models
            for (const [providerId, models] of Object.entries(installedModelsByProvider)) {
                const modelNames = models
                    .map((m) => m.name)
                    .filter(Boolean);
                if (modelNames.length === 0)
                    continue;
                const result = await setupWizardService.upsertProviderModels({
                    providerId,
                    selectedModelIds: modelNames,
                    mode: "updatePricing",
                });
                totalUpdated += result.updatedCount;
                allErrors.push(...result.errors);
            }
            await loadData();
            if (allErrors.length > 0) {
                setError(`Updated ${totalUpdated} models. Errors: ${allErrors.join(", ")}`);
            }
        }
        catch (e) {
            setError(e?.message || "Failed to update pricing");
        }
        finally {
            setUpdatingAllPricing(false);
        }
    };
    const handleUpdate = async (model) => {
        if (!model.id || !model.key)
            return;
        try {
            setUpdating(model.id);
            setError(null);
            await setupWizardService.updateModel({
                modelId: model.id,
                sourceModelKey: model.key,
            });
            await loadData();
        }
        catch (e) {
            setError(e?.message || "Failed to update model");
        }
        finally {
            setUpdating(null);
        }
    };
    const handleDefaultModelsChange = async (nextChatModelId, nextImageModelId) => {
        if (!settingsExists) {
            setError("Parhelia settings item not found");
            return;
        }
        const previousChatModelId = defaultChatModelId;
        const previousImageModelId = defaultImageModelId;
        setDefaultChatModelId(nextChatModelId);
        setDefaultImageModelId(nextImageModelId);
        try {
            setSavingDefaults(true);
            setError(null);
            await setupWizardService.setDefaultModels({
                chatModelId: nextChatModelId,
                imageModelId: nextImageModelId,
            });
        }
        catch (e) {
            setDefaultChatModelId(previousChatModelId);
            setDefaultImageModelId(previousImageModelId);
            setError(e?.message || "Failed to save default models");
        }
        finally {
            setSavingDefaults(false);
        }
    };
    const handleDelete = async (model) => {
        if (!editContext || !model.id)
            return;
        try {
            setDeleting(model.id);
            setError(null);
            const deleted = await editContext.operations.deleteItems([
                {
                    id: model.id,
                    language: editContext.item?.language ??
                        editContext.currentItemDescriptor?.language ??
                        "en",
                    version: 0,
                },
            ]);
            if (deleted) {
                if (selectedModel?.id === model.id) {
                    setSelectedModel(null);
                    updateSelectedModelUrl(null);
                }
                await loadData();
            }
        }
        catch (e) {
            setError(e?.message || "Failed to delete model");
        }
        finally {
            setDeleting(null);
        }
    };
    const openDuplicateDialog = (model) => {
        const segment = model.itemName?.trim() ||
            (model.key.includes("/") && model.key.split("/").length > 0
                ? model.key.split("/").pop()
                : model.name || model.key);
        setDuplicateItemName(`Copy of ${segment}`);
        setDuplicateDialogModel(model);
    };
    const handleConfirmDuplicate = async () => {
        if (!editContext || !duplicateDialogModel?.id) {
            return;
        }
        const parentId = duplicateDialogModel.parentId;
        if (!parentId) {
            return;
        }
        const name = duplicateItemName.trim();
        if (!name) {
            setError("Enter a name for the duplicate item");
            return;
        }
        const model = duplicateDialogModel;
        const lang = editContext.item?.language ??
            editContext.currentItemDescriptor?.language ??
            "en";
        try {
            setDuplicatingId(model.id);
            setError(null);
            const created = await editContext.operations.duplicateItem({ id: model.id, language: lang, version: 0 }, { id: parentId, language: lang, version: 0 }, name);
            if (!created) {
                setDuplicatingId(null);
                return;
            }
            setDuplicateDialogModel(null);
            const list = await loadData();
            if (list) {
                const createdId = String(created.id).replace(/[{}]/g, "").toLowerCase();
                const next = list.find((m) => m.id.replace(/[{}]/g, "").toLowerCase() === createdId);
                if (next) {
                    setSelectedModel(next);
                    updateSelectedModelUrl(next.id);
                }
            }
        }
        catch (e) {
            setError(e?.message || "Failed to duplicate model");
        }
        finally {
            setDuplicatingId(null);
        }
    };
    useEffect(() => {
        loadData();
    }, []);
    const handleNavigateToProviders = () => {
        if (typeof window !== "undefined") {
            window.location.hash = "#providers";
        }
    };
    const chatModels = useMemo(() => installedModels
        .filter((model) => model.templateType === "Ai Chat Model")
        .sort((a, b) => getModelListLabel(a).localeCompare(getModelListLabel(b))), [installedModels]);
    const imageModels = useMemo(() => installedModels
        .filter((model) => model.templateType === "Ai Image Model")
        .sort((a, b) => getModelListLabel(a).localeCompare(getModelListLabel(b))), [installedModels]);
    const chatDefaultConfiguredModel = useMemo(() => chatModels.find((model) => normalizeModelId(model.id) === normalizeModelId(defaultChatModelId)), [chatModels, defaultChatModelId]);
    const imageDefaultConfiguredModel = useMemo(() => imageModels.find((model) => normalizeModelId(model.id) === normalizeModelId(defaultImageModelId)), [imageModels, defaultImageModelId]);
    const chatModelOptions = useMemo(() => {
        const options = [
            { value: "", label: "Not set" },
            ...chatModels.map((model) => ({
                value: model.id,
                label: getModelListLabel(model),
                description: model.providerName || undefined,
            })),
        ];
        if (defaultChatModelId && !chatDefaultConfiguredModel) {
            options.push({
                value: defaultChatModelId,
                label: "Configured model not found",
                description: defaultChatModelId,
            });
        }
        return options;
    }, [chatModels, defaultChatModelId, chatDefaultConfiguredModel]);
    const imageModelOptions = useMemo(() => {
        const options = [
            { value: "", label: "Not set" },
            ...imageModels.map((model) => ({
                value: model.id,
                label: getModelListLabel(model),
                description: model.providerName || undefined,
            })),
        ];
        if (defaultImageModelId && !imageDefaultConfiguredModel) {
            options.push({
                value: defaultImageModelId,
                label: "Configured model not found",
                description: defaultImageModelId,
            });
        }
        return options;
    }, [imageModels, defaultImageModelId, imageDefaultConfiguredModel]);
    // Filter models based on filter text
    const filteredModels = useMemo(() => {
        if (!filterText.trim()) {
            return installedModels;
        }
        const searchTerm = filterText.toLowerCase().trim();
        return installedModels.filter((model) => {
            const listLabel = getModelListLabel(model).toLowerCase();
            const modelName = (model.name || model.key || "").toLowerCase();
            const providerName = (model.providerName || "").toLowerCase();
            const templateType = (model.templateType || "").toLowerCase();
            const modelTypeLabel = getModelTypeLabel(model.templateType || "Ai Chat Model").toLowerCase();
            return (listLabel.includes(searchTerm) ||
                modelName.includes(searchTerm) ||
                providerName.includes(searchTerm) ||
                templateType.includes(searchTerm) ||
                modelTypeLabel.includes(searchTerm));
        });
    }, [installedModels, filterText]);
    // Group models by provider for display
    const groupModelsByProvider = useCallback((models) => {
        const groups = {};
        models.forEach((model) => {
            const providerId = model.providerId || "unknown";
            const provider = providers.find((p) => p.id === providerId);
            const providerName = model.providerName || provider?.name || "Unknown Provider";
            if (!groups[providerId]) {
                groups[providerId] = { providerName, models: [] };
            }
            groups[providerId].models.push(model);
        });
        // Sort models within each group by model type then name
        Object.values(groups).forEach((group) => {
            group.models.sort((a, b) => {
                const typeOrder = (a.templateType || "").localeCompare(b.templateType || "");
                if (typeOrder !== 0)
                    return typeOrder;
                return getModelListLabel(a).localeCompare(getModelListLabel(b));
            });
        });
        return groups;
    }, [providers]);
    const modelsByProvider = useMemo(() => groupModelsByProvider(filteredModels), [filteredModels, groupModelsByProvider]);
    const modelsMissingPricing = useMemo(() => {
        return installedModels.filter((model) => isPricingLineEmpty(model));
    }, [installedModels]);
    // Build the models list content
    const modelsListContent = (_jsx("div", { className: "flex h-full flex-col p-4", children: _jsx("div", { className: "mx-auto flex w-full flex-1 flex-col overflow-hidden", children: _jsxs("div", { className: "flex h-full flex-col overflow-hidden", children: [_jsxs("div", { className: "mt-1 shrink-0", children: [_jsxs("div", { className: "mb-2 rounded-t-lg bg-white p-4", children: [_jsxs("div", { className: "flex flex-wrap items-start justify-between gap-3", children: [_jsxs("div", { children: [_jsx("h2", { className: "text-sm font-semibold text-gray-900", children: "Default models" }), _jsx("p", { className: "mt-1 text-xs text-gray-500", children: "Choose the shared defaults used when a chat or image model is not configured elsewhere." })] }), savingDefaults && (_jsxs("div", { className: "flex items-center gap-2 text-xs text-gray-500", children: [_jsx(RefreshCw, { className: "h-3.5 w-3.5 animate-spin" }), "Saving..."] }))] }), _jsxs("div", { className: "mt-4 grid gap-4 md:grid-cols-2", children: [_jsxs("div", { className: "space-y-2", children: [_jsxs("label", { className: "flex items-center gap-2 text-sm font-medium text-gray-700", children: [_jsx(Brain, { className: "h-4 w-4 text-purple-600", strokeWidth: 1.5 }), "Default chat model"] }), _jsx(Select, { value: defaultChatModelId, onValueChange: (value) => void handleDefaultModelsChange(value, defaultImageModelId), options: chatModelOptions, placeholder: "Select a chat model", disabled: savingDefaults || !settingsExists, searchable: true, searchPlaceholder: "Search chat models..." }), _jsx("p", { className: "text-xs text-gray-500", children: "Used by features that fall back to the settings-level chat model." })] }), _jsxs("div", { className: "space-y-2", children: [_jsxs("label", { className: "flex items-center gap-2 text-sm font-medium text-gray-700", children: [_jsx(Image, { className: "h-4 w-4 text-green-600", strokeWidth: 1.5 }), "Default image model"] }), _jsx(Select, { value: defaultImageModelId, onValueChange: (value) => void handleDefaultModelsChange(defaultChatModelId, value), options: imageModelOptions, placeholder: "Select an image model", disabled: savingDefaults || !settingsExists, searchable: true, searchPlaceholder: "Search image models..." }), _jsx("p", { className: "text-xs text-gray-500", children: "Used by image generation and editing features that rely on the shared default." })] })] }), !settingsExists && (_jsx("div", { className: "mt-4 rounded border border-yellow-200 bg-yellow-50 p-3 text-xs text-yellow-800", children: "Create the Parhelia settings item before saving default models." }))] }), _jsx("div", { className: "rounded-t-lg bg-white p-4", children: _jsxs("div", { className: "flex flex-wrap items-start justify-between gap-3", children: [_jsxs("div", { children: [_jsxs("h2", { className: "text-sm font-semibold text-gray-900", children: ["Installed models (", installedModels.length, ")"] }), _jsx("p", { className: "mt-1 text-xs text-gray-500", children: "Browse, filter, and configure the models available in Parhelia." }), modelsMissingPricing.length > 0 && (_jsxs("div", { className: "mt-3 rounded border border-yellow-200 bg-yellow-50 p-3 text-xs text-yellow-800", children: [modelsMissingPricing.length, " installed model", modelsMissingPricing.length !== 1
                                                            ? "s have"
                                                            : " has", " ", "missing or incomplete pricing information. A warning is shown on each affected model below."] }))] }), _jsx("div", { className: "flex flex-wrap items-center gap-3", children: importableInstalledModels.length > 0 && (_jsxs(Button, { size: "sm", variant: "outline", onClick: handleUpdateAllPricing, disabled: updatingAllPricing, title: "Update pricing for all models from their provider APIs", children: [updatingAllPricing ? (_jsx(RefreshCw, { className: "mr-1 h-4 w-4 animate-spin" })) : (_jsx(RefreshCw, { className: "mr-1 h-4 w-4" })), "Update All Pricing"] })) })] }) }), _jsxs("div", { className: "bg-white px-4", children: [state !== "loading" && providers.length === 0 && (_jsx("div", { className: "rounded border border-yellow-200 bg-yellow-50 p-4", children: _jsxs("div", { className: "flex items-start gap-3", children: [_jsx(AlertCircle, { className: "mt-0.5 h-5 w-5 shrink-0 text-yellow-600" }), _jsxs("div", { className: "flex-1", children: [_jsx("p", { className: "mb-1 text-sm font-medium text-yellow-800", children: "No providers configured" }), _jsx("p", { className: "mb-3 text-xs text-yellow-700", children: "You need to configure at least one provider before you can add models." }), _jsxs(Button, { size: "sm", variant: "outline", onClick: handleNavigateToProviders, className: "text-xs", children: ["Go to Providers", _jsx(ArrowRight, { className: "ml-1 h-3 w-3" })] })] })] }) })), providers.length > 0 && (_jsxs("div", { className: "mb-4 flex gap-2", children: [importableProviders.length > 0 && (_jsxs(Button, { size: "sm", variant: "outline", onClick: () => {
                                                    setShowImportDialog(true);
                                                    setError(null);
                                                }, children: [_jsx(Cloud, { strokeWidth: 1, className: "mr-1 h-4 w-4" }), "Import from Provider"] })), _jsxs(Button, { size: "sm", variant: "outline", onClick: () => {
                                                    setShowAddDialog(true);
                                                    setError(null);
                                                }, children: [_jsx(Plus, { strokeWidth: 1, className: "mr-1 h-4 w-4" }), "Add Manually"] })] })), error && (_jsx("div", { className: "rounded border border-red-200 bg-red-50 p-2 text-xs whitespace-pre-wrap text-red-700", children: error })), _jsx(FilterInput, { value: filterText, onChange: setFilterText, placeholder: "Filter models by name, provider, or type...", className: "mb-4 w-full" })] })] }), _jsx("div", { className: "min-h-0 flex-1 overflow-y-auto rounded-b-lg bg-white px-4 pb-4", children: filterText && filteredModels.length === 0 ? (_jsxs("div", { className: "flex items-center justify-center py-8 text-sm text-gray-500", children: ["No models found matching ", `"${filterText}"`] })) : (_jsx("div", { className: "space-y-4", children: Object.entries(modelsByProvider).map(([providerId, { providerName, models }]) => {
                                if (models.length === 0)
                                    return null;
                                return (_jsxs("div", { className: "space-y-2", children: [_jsxs("label", { className: "block text-sm font-medium text-gray-700", children: [providerName, _jsxs("span", { className: "ml-2 text-xs font-normal text-gray-500", children: ["(", models.length, " model", models.length !== 1 ? "s" : "", ")"] })] }), _jsx("div", { className: "space-y-2", children: models.map((model) => {
                                                const status = model.status;
                                                const isSelected = selectedModel?.id === model.id;
                                                const showPricingLine = hasVisiblePricingSummary(model);
                                                return (_jsxs("div", { className: `flex flex-wrap items-center gap-2 rounded border p-3 text-sm transition-shadow hover:shadow-sm ${isSelected
                                                        ? "border-blue-400 bg-blue-50"
                                                        : "border-gray-200 bg-white"}`, children: [_jsxs("div", { className: "min-w-0 flex-1", children: [_jsxs("div", { className: "flex flex-wrap items-center gap-2", children: [_jsx("span", { className: "truncate font-medium", children: getModelListLabel(model) }), _jsx("span", { className: "shrink-0 rounded bg-gray-100 px-1.5 py-0.5 text-xs text-gray-600", children: getModelTypeLabel(model.templateType || "Ai Chat Model") }), normalizeModelId(model.id) ===
                                                                            normalizeModelId(defaultChatModelId) && (_jsx("span", { className: "shrink-0 rounded bg-purple-100 px-1.5 py-0.5 text-xs text-purple-700", children: "Default chat" })), normalizeModelId(model.id) ===
                                                                            normalizeModelId(defaultImageModelId) && (_jsx("span", { className: "shrink-0 rounded bg-green-100 px-1.5 py-0.5 text-xs text-green-700", children: "Default image" })), status === "Outdated" && (_jsx("span", { className: "shrink-0 rounded bg-amber-100 px-1.5 py-0.5 text-xs text-amber-700", children: "Update available" })), !showPricingLine && (_jsx("span", { className: "shrink-0 rounded bg-yellow-100 px-1.5 py-0.5 text-xs text-yellow-800", children: "Pricing missing" }))] }), showPricingLine && model.pricing ? (_jsx("div", { className: "mt-1 text-xs text-gray-500", children: model.templateType ===
                                                                        "Ai Image Model" &&
                                                                        hasUsableImagePricing(model) ? (_jsxs(_Fragment, { children: [hasDefinedPricingValue(model.pricing.inputTextTokenCostPerMillion) && (_jsxs("span", { children: ["Input Text: $", model.pricing.inputTextTokenCostPerMillion.toFixed(2), "/M"] })), hasDefinedPricingValue(model.pricing.inputImageTokenCostPerMillion) && (_jsxs("span", { className: "ml-2", children: ["Input Image: $", model.pricing.inputImageTokenCostPerMillion.toFixed(2), "/M"] })), hasDefinedPricingValue(model.pricing.outputImageTokenCostPerMillion) && (_jsxs("span", { className: "ml-2", children: ["Output Image: $", model.pricing.outputImageTokenCostPerMillion.toFixed(2), "/M"] }))] })) : (_jsxs(_Fragment, { children: [hasDefinedPricingValue(model.pricing
                                                                                .inputCostPerMillionTokens) && (_jsxs("span", { children: ["Input: $", model.pricing.inputCostPerMillionTokens.toFixed(2), "/M"] })), hasDefinedPricingValue(model.pricing
                                                                                .outputCostPerMillionTokens) && (_jsxs("span", { className: "ml-2", children: ["Output: $", model.pricing.outputCostPerMillionTokens.toFixed(2), "/M"] })), hasDefinedPricingValue(model.pricing
                                                                                .cachedInputCostPerMillionTokens) && (_jsxs("span", { className: "ml-2", children: ["Cached: $", model.pricing.cachedInputCostPerMillionTokens.toFixed(2), "/M"] }))] })) })) : (_jsxs("div", { className: "mt-1 flex items-start gap-2 rounded border border-yellow-200 bg-yellow-50 px-2 py-1.5 text-xs text-yellow-800", children: [_jsx(AlertCircle, { className: "mt-0.5 h-3.5 w-3.5 shrink-0" }), _jsx("span", { children: getPricingWarningMessage(model) })] })), (model.maxContextWindowTokens ||
                                                                    model.maxResponseTokens) && (_jsxs("div", { className: "mt-1 text-xs text-gray-500", children: [model.maxContextWindowTokens && (_jsxs("span", { children: ["Context:", " ", model.maxContextWindowTokens.toLocaleString(), " ", "tokens"] })), model.maxContextWindowTokens &&
                                                                            model.maxResponseTokens &&
                                                                            " • ", model.maxResponseTokens && (_jsxs("span", { children: ["Max Response:", " ", model.maxResponseTokens.toLocaleString(), " ", "tokens"] }))] }))] }), _jsxs("div", { className: "flex shrink-0 items-center gap-1", children: [status === "Outdated" && (_jsxs(Button, { size: "sm", variant: "outline", onClick: () => handleUpdate(model), disabled: updating === model.id, title: "Update model", children: [updating === model.id ? (_jsx(RefreshCw, { strokeWidth: 1, className: "h-3 w-3 animate-spin" })) : (_jsx(Upload, { strokeWidth: 1, className: "h-3 w-3" })), _jsx("span", { className: "ml-1 hidden sm:inline", children: "Update" })] })), _jsxs(Button, { size: "sm", variant: isSelected ? "default" : "ghost", onClick: () => handleOpenConfig(model), title: "Configure model", children: [_jsx(Settings, { className: "h-4 w-4", strokeWidth: 1.5 }), _jsx("span", { className: "ml-1 hidden sm:inline", children: "Configure" })] }), _jsxs(Button, { size: "sm", variant: "ghost", onClick: () => openDuplicateDialog(model), disabled: !editContext ||
                                                                        !model.parentId ||
                                                                        duplicatingId === model.id, title: "Duplicate model", children: [duplicatingId === model.id ? (_jsx(RefreshCw, { strokeWidth: 1, className: "h-3 w-3 animate-spin" })) : (_jsx(Copy, { strokeWidth: 1, className: "h-3 w-3" })), _jsx("span", { className: "ml-1 hidden sm:inline", children: "Duplicate" })] }), _jsx(Button, { size: "sm", variant: "ghost", onClick: () => handleDelete(model), disabled: deleting === model.id, title: "Delete model", className: "text-red-600 hover:bg-red-50 hover:text-red-700", children: deleting === model.id ? (_jsx(RefreshCw, { strokeWidth: 1, className: "h-3 w-3 animate-spin" })) : (_jsx(Trash2, { strokeWidth: 1, className: "h-3 w-3" })) })] })] }, model.id));
                                            }) })] }, providerId));
                            }) })) }), _jsx(AddModelDialog, { open: showAddDialog, onOpenChange: setShowAddDialog, onSuccess: loadData, providers: providers, installedModels: installedModels }), _jsx(ImportModelDialog, { open: showImportDialog, onOpenChange: setShowImportDialog, onSuccess: loadData, importableProviders: importableProviders, providerTypes: providerTypes }), _jsx(Dialog, { open: duplicateDialogModel !== null, onOpenChange: (open) => {
                            if (!open)
                                setDuplicateDialogModel(null);
                        }, children: _jsxs(DialogContent, { className: "max-w-md", children: [_jsxs(DialogHeader, { className: "pr-14", children: [_jsx(DialogTitle, { children: "Duplicate model" }), _jsx(DialogDescription, { children: "New Sitecore item name. Field values (including model name and reasoning) are copied; adjust them in Configure after duplicating." })] }), _jsxs("div", { className: "space-y-2 px-8 pb-6", children: [_jsx("label", { htmlFor: "duplicate-model-item-name", className: "block text-sm font-medium text-gray-700", children: "Item name" }), _jsx(Input, { id: "duplicate-model-item-name", value: duplicateItemName, onChange: (e) => setDuplicateItemName(e.target.value), onKeyDown: (e) => {
                                                if (e.key === "Enter") {
                                                    e.preventDefault();
                                                    void handleConfirmDuplicate();
                                                }
                                            }, autoFocus: true })] }), _jsxs(DialogFooter, { className: "border-t border-gray-100 pt-4", children: [_jsx(Button, { type: "button", variant: "outline", className: "min-h-9 min-w-22", onClick: () => setDuplicateDialogModel(null), children: "Cancel" }), _jsx(Button, { type: "button", className: "min-h-9 min-w-22", onClick: () => void handleConfirmDuplicate(), disabled: !duplicateItemName.trim() ||
                                                (duplicateDialogModel != null &&
                                                    duplicatingId === duplicateDialogModel.id), children: duplicateDialogModel != null &&
                                                duplicatingId === duplicateDialogModel.id ? (_jsxs(_Fragment, { children: [_jsx(RefreshCw, { className: "mr-1 h-4 w-4 animate-spin" }), "Duplicating\u2026"] })) : ("Duplicate") })] })] }) })] }) }) }));
    // Build splitter panels - only show config panel when a model is selected
    const panels = selectedModel?.id
        ? [
            {
                name: "models-list",
                defaultSize: "auto",
                content: modelsListContent,
                className: "overflow-hidden",
            },
            {
                name: "model-config",
                defaultSize: 400,
                content: (_jsx(ModelConfigPanel, { itemId: selectedModel.id, title: `Configure: ${getModelListLabel(selectedModel) || "Model"}`, onClose: handleCloseConfig, onModelRenamed: async () => {
                        await loadData();
                    } }, selectedModel.id)),
                className: "overflow-hidden",
            },
        ]
        : [
            {
                name: "models-list",
                defaultSize: "auto",
                content: modelsListContent,
                className: "overflow-hidden",
            },
        ];
    return (_jsx(Splitter, { panels: panels, localStorageKey: "models-panel-splitter", direction: "horizontal", className: "h-full" }));
}
export default ModelsPanel;
//# sourceMappingURL=ModelsPanel.js.map