import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
import { useCallback, useState, useMemo, useEffect, useRef, } from "react";
import { Dialog, DialogContent } from "../../../components/ui/dialog";
import { Button } from "../../../components/ui/button";
import { Select } from "../../../components/ui/select";
import { Input } from "../../../components/ui/input";
import { StyledDialogTitle } from "../../../components/ui/styled-dialog-title";
import { setupWizardService, } from "../../services/setupWizardService";
import { RefreshCw, Upload, Plus, Search, Square, CheckSquare, ExternalLink, AlertTriangle, } from "lucide-react";
import { useEditContext } from "../../../editor/client/editContext";
const roundsToNonZero = (value, decimals) => {
    if (value === undefined || value === null)
        return false;
    return Number(value.toFixed(decimals)) > 0;
};
const hasUsableImagePricing = (model) => roundsToNonZero(model.pricing?.requestCost, 4) ||
    roundsToNonZero(model.pricing?.imageCost, 4) ||
    roundsToNonZero(model.pricing?.imageOutputCost, 4) ||
    roundsToNonZero(model.pricing?.inputTextTokenCostPerMillion, 2) ||
    roundsToNonZero(model.pricing?.inputImageTokenCostPerMillion, 2) ||
    roundsToNonZero(model.pricing?.outputImageTokenCostPerMillion, 2);
export function ImportModelDialog({ open, onOpenChange, onSuccess, importableProviders, providerTypes = [], }) {
    const editContext = useEditContext();
    const [error, setError] = useState(null);
    // Import from provider state
    const [importProviderId, setImportProviderId] = useState(importableProviders[0]?.id || "");
    const [providerModels, setProviderModels] = useState([]);
    const [loadingProviderModels, setLoadingProviderModels] = useState(false);
    const [selectedModelIds, setSelectedModelIds] = useState(new Set());
    const [importing, setImporting] = useState(false);
    const [updatingPricing, setUpdatingPricing] = useState(false);
    const [importSearchQuery, setImportSearchQuery] = useState("");
    const [importTypeFilter, setImportTypeFilter] = useState("all");
    const [importStatusFilter, setImportStatusFilter] = useState("all");
    // Check if the selected provider uses a static catalog
    const selectedProviderType = useMemo(() => {
        const provider = importableProviders.find((p) => p.id === importProviderId);
        if (!provider)
            return null;
        return providerTypes.find((pt) => pt.providerId === provider.type);
    }, [importProviderId, importableProviders, providerTypes]);
    const isStaticCatalog = selectedProviderType?.isStaticCatalog ?? false;
    // Track previous open state to detect open transitions
    const wasOpenRef = useRef(false);
    // Reset state only when dialog transitions from closed to open
    useEffect(() => {
        if (open && !wasOpenRef.current) {
            setError(null);
            setImportProviderId(importableProviders[0]?.id || "");
            setProviderModels([]);
            setSelectedModelIds(new Set());
            setImportSearchQuery("");
            setImportTypeFilter("all");
            setImportStatusFilter("all");
            setImporting(false);
            setUpdatingPricing(false);
        }
        wasOpenRef.current = open;
    }, [open, importableProviders]);
    // Automatically load models when provider is selected
    useEffect(() => {
        if (!open || !importProviderId) {
            return;
        }
        let cancelled = false;
        const loadModels = async () => {
            try {
                setLoadingProviderModels(true);
                setError(null);
                const models = await setupWizardService.getProviderModels(importProviderId);
                if (!cancelled) {
                    setProviderModels(models);
                    setSelectedModelIds(new Set());
                }
            }
            catch (e) {
                if (!cancelled) {
                    setError(e?.message || "Failed to load models from provider");
                }
            }
            finally {
                if (!cancelled) {
                    setLoadingProviderModels(false);
                }
            }
        };
        loadModels();
        return () => {
            cancelled = true;
        };
    }, [open, importProviderId]);
    // Load models from provider
    const handleLoadProviderModels = useCallback(async () => {
        if (!importProviderId) {
            setError("Please select a provider first");
            return;
        }
        try {
            setLoadingProviderModels(true);
            setError(null);
            const models = await setupWizardService.getProviderModels(importProviderId);
            setProviderModels(models);
            setSelectedModelIds(new Set());
        }
        catch (e) {
            setError(e?.message || "Failed to load models from provider");
        }
        finally {
            setLoadingProviderModels(false);
        }
    }, [importProviderId]);
    // Filter provider models
    const filteredProviderModels = useMemo(() => {
        return providerModels.filter((model) => {
            // Search filter
            if (importSearchQuery) {
                const query = importSearchQuery.toLowerCase();
                if (!model.id.toLowerCase().includes(query) &&
                    !model.name.toLowerCase().includes(query) &&
                    !model.provider.toLowerCase().includes(query)) {
                    return false;
                }
            }
            // Type filter
            if (importTypeFilter !== "all" && model.modelType !== importTypeFilter) {
                return false;
            }
            // Status filter
            if (importStatusFilter === "missing" && model.isInstalled) {
                return false;
            }
            if (importStatusFilter === "installed" && !model.isInstalled) {
                return false;
            }
            if (importStatusFilter === "pricingDiffers" && !model.pricingDiffers) {
                return false;
            }
            return true;
        });
    }, [providerModels, importSearchQuery, importTypeFilter, importStatusFilter]);
    // Group models by provider
    const groupedProviderModels = useMemo(() => {
        const groups = {};
        filteredProviderModels.forEach((model) => {
            const provider = model.provider || "other";
            if (!groups[provider]) {
                groups[provider] = [];
            }
            groups[provider].push(model);
        });
        // Sort groups by provider name
        return Object.entries(groups).sort(([a], [b]) => a.localeCompare(b));
    }, [filteredProviderModels]);
    // Toggle model selection
    const toggleModelSelection = useCallback((modelId) => {
        setSelectedModelIds((prev) => {
            const next = new Set(prev);
            if (next.has(modelId)) {
                next.delete(modelId);
            }
            else {
                next.add(modelId);
            }
            return next;
        });
    }, []);
    // Select/deselect all visible models
    const toggleSelectAll = useCallback(() => {
        const visibleIds = filteredProviderModels.map((m) => m.id);
        const allSelected = visibleIds.every((id) => selectedModelIds.has(id));
        if (allSelected) {
            setSelectedModelIds((prev) => {
                const next = new Set(prev);
                visibleIds.forEach((id) => next.delete(id));
                return next;
            });
        }
        else {
            setSelectedModelIds((prev) => {
                const next = new Set(prev);
                visibleIds.forEach((id) => next.add(id));
                return next;
            });
        }
    }, [filteredProviderModels, selectedModelIds]);
    // Import selected models
    const handleImportSelected = useCallback(async () => {
        if (selectedModelIds.size === 0) {
            setError("Please select at least one model to import");
            return;
        }
        try {
            setImporting(true);
            setError(null);
            const result = await setupWizardService.upsertProviderModels({
                providerId: importProviderId,
                selectedModelIds: Array.from(selectedModelIds),
                mode: "createMissing",
            });
            // Update local state optimistically to mark imported models as installed
            // This avoids reloading the entire list and showing the spinner
            if (result.createdCount > 0) {
                setProviderModels((prevModels) => prevModels.map((model) => selectedModelIds.has(model.id)
                    ? { ...model, isInstalled: true, pricingDiffers: false }
                    : model));
            }
            // Clear selection after successful import
            setSelectedModelIds(new Set());
            // Refresh the parent's installed models list
            onSuccess();
            // Show result
            if (result.errors.length > 0) {
                setError(`Created ${result.createdCount} models. Errors: ${result.errors.join(", ")}`);
            }
        }
        catch (e) {
            setError(e?.message || "Failed to import models");
        }
        finally {
            setImporting(false);
        }
    }, [importProviderId, selectedModelIds, onSuccess]);
    // Update pricing for selected models
    const handleUpdatePricing = useCallback(async () => {
        if (selectedModelIds.size === 0) {
            setError("Please select at least one model to update");
            return;
        }
        try {
            setUpdatingPricing(true);
            setError(null);
            const result = await setupWizardService.upsertProviderModels({
                providerId: importProviderId,
                selectedModelIds: Array.from(selectedModelIds),
                mode: "updatePricing",
            });
            // Update local state optimistically to clear pricing differences
            // This avoids reloading the entire list and showing the spinner
            if (result.updatedCount > 0) {
                setProviderModels((prevModels) => prevModels.map((model) => selectedModelIds.has(model.id)
                    ? { ...model, pricingDiffers: false }
                    : model));
            }
            // Refresh the parent's installed models list
            onSuccess();
            // Show result
            if (result.errors.length > 0) {
                setError(`Updated ${result.updatedCount} models. Errors: ${result.errors.join(", ")}`);
            }
        }
        catch (e) {
            setError(e?.message || "Failed to update pricing");
        }
        finally {
            setUpdatingPricing(false);
        }
    }, [importProviderId, selectedModelIds, onSuccess]);
    return (_jsx(Dialog, { open: open, onOpenChange: onOpenChange, children: _jsxs(DialogContent, { className: "flex h-[85vh] max-w-3xl flex-col", children: [_jsx(StyledDialogTitle, { icon: _jsx(Upload, { strokeWidth: 1 }), title: "Import Models from Provider" }), _jsxs("div", { className: "flex flex-col gap-4 overflow-hidden p-6", children: [_jsxs("div", { className: "grid grid-cols-1 gap-4 sm:grid-cols-2", children: [_jsxs("div", { className: "space-y-1.5", children: [_jsx("label", { className: "text-neutral-grey-50 text-xs font-semibold tracking-wider", children: "Provider" }), _jsx(Select, { value: importProviderId, onValueChange: (value) => {
                                                setImportProviderId(value);
                                                setProviderModels([]);
                                                setSelectedModelIds(new Set());
                                            }, options: importableProviders.map((provider) => ({
                                                value: provider.id,
                                                label: provider.name,
                                            })), placeholder: "Select provider" }), loadingProviderModels && (_jsxs("div", { className: "text-neutral-grey-50 flex items-center gap-2 text-xs", children: [_jsx(RefreshCw, { className: "h-3 w-3 animate-spin" }), "Loading catalog..."] }))] }), importProviderId && (_jsxs("div", { className: "space-y-1.5", children: [_jsx("label", { className: "text-neutral-grey-50 text-xs font-semibold tracking-wider", children: "Model Type" }), _jsx(Select, { value: importTypeFilter, onValueChange: (value) => setImportTypeFilter(value), options: [
                                                { value: "all", label: "All Types" },
                                                { value: "chat", label: "Chat Models" },
                                                { value: "embeddings", label: "Embeddings" },
                                                { value: "image", label: "Image" },
                                            ] })] }))] }), (isStaticCatalog || importProviderId) && (_jsxs("div", { className: `flex flex-col gap-2 rounded-lg border p-3 text-sm ${isStaticCatalog
                                ? "border-feedback-orange bg-feedback-orange-light text-feedback-orange"
                                : "border-feedback-blue bg-feedback-blue-light text-feedback-blue"}`, children: [isStaticCatalog && (_jsxs("div", { className: "flex items-start gap-2", children: [_jsx(AlertTriangle, { className: "mt-0.5 h-4 w-4 shrink-0" }), _jsx("p", { children: "This provider's model catalog is maintained manually and may not include the latest models or pricing." })] })), importProviderId && (_jsxs("div", { className: "flex items-start gap-2", children: [_jsx(AlertTriangle, { className: `mt-0.5 h-4 w-4 shrink-0 ${isStaticCatalog ? "text-feedback-orange" : "text-feedback-blue"}` }), _jsx("p", { children: isStaticCatalog
                                                ? "Model availability and pricing for this provider are maintained manually and may lag behind the live provider catalog."
                                                : "Pricing is retrieved from the provider's API and may not be 100% precise. Please verify on the provider's website." })] }))] })), providerModels.length > 0 && (_jsxs(_Fragment, { children: [_jsxs("div", { className: "flex flex-col gap-3", children: [_jsxs("div", { className: "flex flex-wrap items-center gap-2", children: [_jsxs("div", { className: "relative min-w-48 flex-1", children: [_jsx(Search, { className: "text-neutral-grey-50 absolute top-1/2 left-3 h-4 w-4 -translate-y-1/2" }), _jsx(Input, { type: "text", placeholder: "Search models by name or ID...", value: importSearchQuery, onChange: (e) => setImportSearchQuery(e.target.value), className: "border-border-default focus:border-feedback-blue focus:ring-feedback-blue h-10 pl-9" })] }), _jsx(Select, { value: importStatusFilter, onValueChange: (value) => setImportStatusFilter(value), options: [
                                                        { value: "all", label: "All Status" },
                                                        { value: "missing", label: "Not Installed" },
                                                        { value: "installed", label: "Installed" },
                                                        { value: "pricingDiffers", label: "Pricing Differs" },
                                                    ], className: "h-10 w-44" })] }), _jsxs("div", { className: "border-border-default bg-neutral-grey-5/50 flex items-center justify-between gap-3 rounded-lg border p-2", children: [_jsxs("div", { className: "flex items-center gap-2 pl-1", children: [_jsx("button", { onClick: toggleSelectAll, className: "text-neutral-grey-50 hover:text-feedback-blue flex items-center gap-2 text-xs font-medium transition-colors", children: filteredProviderModels.every((m) => selectedModelIds.has(m.id)) ? (_jsxs(_Fragment, { children: [_jsx(CheckSquare, { className: "text-feedback-blue h-4 w-4" }), _jsx("span", { children: "Deselect All" })] })) : (_jsxs(_Fragment, { children: [_jsx(Square, { className: "h-4 w-4" }), _jsx("span", { children: "Select All" })] })) }), _jsx("div", { className: "bg-border-default mx-1 h-4 w-px" }), _jsxs("span", { className: "text-neutral-grey-50 text-xs font-medium", children: [selectedModelIds.size > 0 ? (_jsxs("span", { className: "text-feedback-blue", children: [selectedModelIds.size, " selected"] })) : ("None selected"), _jsx("span", { className: "mx-1 opacity-50", children: "\u2022" }), filteredProviderModels.length, " visible"] })] }), _jsx("div", { className: "flex gap-1.5", children: selectedModelIds.size > 0 && (_jsxs(_Fragment, { children: [_jsxs(Button, { size: "sm", onClick: handleImportSelected, disabled: importing || updatingPricing, className: "shadow-feedback-blue h-8 px-3 shadow-sm", children: [importing ? (_jsx(RefreshCw, { className: "mr-2 h-3.5 w-3.5 animate-spin" })) : (_jsx(Plus, { className: "mr-2 h-3.5 w-3.5" })), "Import"] }), _jsxs(Button, { size: "sm", variant: "outline", onClick: handleUpdatePricing, disabled: importing || updatingPricing, className: "h-8 px-3", children: [updatingPricing ? (_jsx(RefreshCw, { className: "mr-2 h-3.5 w-3.5 animate-spin" })) : (_jsx(Upload, { className: "mr-2 h-3.5 w-3.5" })), "Update Pricing"] })] })) })] })] }), _jsxs("div", { className: "border-border-default min-h-0 flex-1 overflow-y-auto rounded-xl border bg-white shadow-inner", children: [groupedProviderModels.map(([provider, models]) => (_jsxs("div", { className: "border-border-default border-b last:border-0", children: [_jsxs("div", { className: "border-border-default/50 bg-neutral-grey-5/90 text-neutral-grey-50 sticky top-0 z-10 flex items-center justify-between border-b px-4 py-2 text-[11px] font-bold tracking-widest backdrop-blur", children: [_jsx("span", { children: provider }), _jsx("span", { className: "rounded-badge bg-neutral-grey-10/50 badge-pad-sm text-neutral-grey-50 font-medium tracking-normal lowercase", children: models.length })] }), _jsx("div", { className: "divide-border-default divide-y p-2", children: models.map((model) => (_jsxs("div", { className: `group flex cursor-pointer items-start gap-3 rounded-lg p-3 transition-all ${selectedModelIds.has(model.id)
                                                            ? "bg-feedback-blue-light/80 ring-feedback-blue ring-1"
                                                            : "hover:bg-neutral-grey-5"}`, onClick: () => toggleModelSelection(model.id), children: [_jsx("div", { className: "mt-0.5 shrink-0", children: selectedModelIds.has(model.id) ? (_jsx("div", { className: "bg-feedback-blue rounded p-0.5 shadow-sm", children: _jsx(CheckSquare, { className: "h-3.5 w-3.5 text-white" }) })) : (_jsx(Square, { className: "text-neutral-grey-50 group-hover:text-feedback-blue h-4.5 w-4.5 transition-colors" })) }), _jsxs("div", { className: "min-w-0 flex-1", children: [_jsxs("div", { className: "flex flex-wrap items-center gap-x-2 gap-y-1", children: [_jsx("span", { className: "text-neutral-grey-100 truncate text-sm font-semibold", children: model.name || model.id }), _jsxs("div", { className: "flex flex-wrap gap-1", children: [model.isInstalled && (_jsx("span", { className: "rounded-badge bg-feedback-green-light badge-pad-sm text-2xs text-feedback-green ring-feedback-green/20 inline-flex items-center font-bold ring-1 ring-inset", children: "Installed" })), model.pricingDiffers && (_jsx("span", { className: "rounded-badge bg-feedback-orange-light badge-pad-sm text-2xs text-feedback-orange ring-feedback-orange/20 inline-flex items-center font-bold ring-1 ring-inset", children: "Update available" })), _jsx("span", { className: "rounded-badge bg-neutral-grey-5 badge-pad-sm text-2xs text-neutral-grey-50 inline-flex items-center font-medium", children: model.modelType })] }), model.isInstalled && model.installedItemId && (_jsx("button", { onClick: async (e) => {
                                                                                    e.stopPropagation();
                                                                                    await editContext?.loadItem(model.installedItemId);
                                                                                    editContext?.switchWorkspace("editor");
                                                                                }, className: "text-neutral-grey-50 hover:bg-feedback-blue-light hover:text-feedback-blue ml-auto rounded-md p-1 transition-colors", title: "Load item in editor", children: _jsx(ExternalLink, { className: "h-3.5 w-3.5", strokeWidth: 2 }) }))] }), _jsxs("div", { className: "text-neutral-grey-50 mt-1 flex items-center gap-2 text-[11px] font-medium", children: [model.pricing && (_jsx("div", { className: "flex items-center gap-1.5", children: model.modelType === "image" &&
                                                                                    hasUsableImagePricing(model) ? (_jsxs(_Fragment, { children: [model.pricing.requestCost !==
                                                                                            undefined && (_jsxs("span", { className: "border-border-default bg-neutral-grey-5 badge-pad-sm rounded border", children: ["Request: $", model.pricing.requestCost.toFixed(4)] })), model.pricing.imageCost !==
                                                                                            undefined && (_jsxs("span", { className: "border-border-default bg-neutral-grey-5 badge-pad-sm rounded border", children: ["Image: $", model.pricing.imageCost.toFixed(4)] })), model.pricing.imageOutputCost !==
                                                                                            undefined && (_jsxs("span", { className: "border-border-default bg-neutral-grey-5 badge-pad-sm rounded border", children: ["Out Image: $", model.pricing.imageOutputCost.toFixed(4)] })), model.pricing
                                                                                            .inputTextTokenCostPerMillion !==
                                                                                            undefined && (_jsxs("span", { className: "border-border-default bg-neutral-grey-5 badge-pad-sm rounded border", children: ["In Text: $", model.pricing.inputTextTokenCostPerMillion.toFixed(2), "/M"] })), model.pricing
                                                                                            .inputImageTokenCostPerMillion !==
                                                                                            undefined && (_jsxs("span", { className: "border-border-default bg-neutral-grey-5 badge-pad-sm rounded border", children: ["In Image: $", model.pricing.inputImageTokenCostPerMillion.toFixed(2), "/M"] })), model.pricing
                                                                                            .outputImageTokenCostPerMillion !==
                                                                                            undefined && (_jsxs("span", { className: "border-border-default bg-neutral-grey-5 badge-pad-sm rounded border", children: ["Out Image: $", model.pricing.outputImageTokenCostPerMillion.toFixed(2), "/M"] }))] })) : (_jsxs(_Fragment, { children: [_jsxs("span", { className: "border-border-default bg-neutral-grey-5 badge-pad-sm rounded border", children: ["In: $", model.pricing.inputCostPerMillionTokens?.toFixed(2) || "0.00", "/M"] }), model.pricing
                                                                                            .outputCostPerMillionTokens !==
                                                                                            undefined && (_jsxs("span", { className: "border-border-default bg-neutral-grey-5 badge-pad-sm rounded border", children: ["Out: $", model.pricing.outputCostPerMillionTokens.toFixed(2), "/M"] }))] })) })), model.contextLength && (_jsxs("span", { className: "flex items-center gap-1", children: [_jsx("span", { className: "bg-neutral-grey-10 h-1 w-1 rounded-full" }), (model.contextLength / 1000).toFixed(0), "k context"] })), _jsx("span", { className: "text-neutral-grey-50 ml-auto hidden font-mono text-[10px] sm:block", children: model.id })] })] })] }, model.id))) })] }, provider))), filteredProviderModels.length === 0 && (_jsx("div", { className: "text-neutral-grey-50 py-12 text-center", children: "No models match your filters" }))] })] })), error && (_jsx("div", { className: "border-feedback-red bg-feedback-red-light text-feedback-red rounded-md border p-3 text-sm", children: error })), _jsx("div", { className: "border-border-default flex justify-end gap-3 border-t pt-4", children: _jsx(Button, { variant: "outline", onClick: () => onOpenChange(false), children: "Close" }) })] })] }) }));
}
export default ImportModelDialog;
//# sourceMappingURL=ImportModelDialog.js.map