import React from 'react';
import { useLocalStorageState } from '../hooks/useLocalStorage';
const EMPTY_STATE = {
    byId: {},
    order: [],
    defaultModelId: null
};
const sanitizeIdSegment = (value) => value.toLowerCase().replace(/[^a-z0-9]+/g, '-').replace(/^-+|-+$/g, '');
const ensureModelId = (model, usedIds) => {
    const candidateId = typeof model.id === 'string' ? model.id.trim() : '';
    if (candidateId.length > 0) {
        usedIds.add(candidateId);
        return candidateId;
    }
    const baseDescriptor = [model.provider, model.model].filter(Boolean).join('-');
    const baseId = `prop-${sanitizeIdSegment(baseDescriptor) || 'model'}`;
    let candidate = baseId;
    let suffix = 1;
    while (usedIds.has(candidate)) {
        candidate = `${baseId}-${suffix++}`;
    }
    usedIds.add(candidate);
    return candidate;
};
const modelsEqual = (a, b) => JSON.stringify(a) === JSON.stringify(b);
const ModelContext = React.createContext(undefined);
const generateModelId = () => {
    if (typeof crypto !== 'undefined' && 'randomUUID' in crypto) {
        return crypto.randomUUID();
    }
    return `model-${Date.now()}-${Math.random().toString(16).slice(2, 8)}`;
};
export const ModelProvider = ({ children, initialModels, storageKey = 'llm-models' }) => {
    const { value: state, update: updateState, setValue } = useLocalStorageState(storageKey, EMPTY_STATE);
    React.useEffect(() => {
        if (!initialModels?.length)
            return;
        updateState((prev) => {
            let nextById = prev.byId;
            let nextOrder = prev.order;
            let nextDefaultId = prev.defaultModelId;
            let changed = false;
            const usedIds = new Set(nextOrder);
            initialModels.forEach((incomingModel) => {
                const normalized = { ...incomingModel };
                const id = ensureModelId(normalized, usedIds);
                normalized.id = id;
                const existing = nextById[id];
                if (existing) {
                    const merged = {
                        ...existing,
                        ...normalized,
                        id
                    };
                    if (!modelsEqual(existing, merged)) {
                        nextById = {
                            ...nextById,
                            [id]: merged
                        };
                        changed = true;
                    }
                }
                else {
                    nextById = {
                        ...nextById,
                        [id]: normalized
                    };
                    if (!nextOrder.includes(id)) {
                        nextOrder = [...nextOrder, id];
                    }
                    if (!nextDefaultId) {
                        nextDefaultId = id;
                    }
                    changed = true;
                }
            });
            if (!changed) {
                return prev;
            }
            if (nextDefaultId && !nextById[nextDefaultId]) {
                nextDefaultId = nextOrder[0] ?? null;
            }
            return {
                byId: nextById,
                order: nextOrder,
                defaultModelId: nextDefaultId
            };
        });
    }, [initialModels, updateState]);
    const addModel = React.useCallback((model) => {
        const id = model.id ?? generateModelId();
        updateState((prev) => {
            const exists = prev.byId[id];
            const order = exists ? prev.order : [...prev.order, id];
            return {
                byId: {
                    ...prev.byId,
                    [id]: { ...model, id }
                },
                order,
                defaultModelId: prev.defaultModelId ?? id
            };
        });
        return id;
    }, [updateState]);
    const updateModel = React.useCallback((id, patch) => {
        updateState((prev) => {
            const current = prev.byId[id];
            if (!current)
                return prev;
            return {
                ...prev,
                byId: {
                    ...prev.byId,
                    [id]: { ...current, ...patch, id }
                }
            };
        });
    }, [updateState]);
    const removeModel = React.useCallback((id) => {
        updateState((prev) => {
            if (!prev.byId[id])
                return prev;
            const nextById = { ...prev.byId };
            delete nextById[id];
            const nextOrder = prev.order.filter((entryId) => entryId !== id);
            const nextDefault = prev.defaultModelId === id ? (nextOrder[0] ?? null) : prev.defaultModelId;
            return {
                byId: nextById,
                order: nextOrder,
                defaultModelId: nextDefault
            };
        });
    }, [updateState]);
    const setDefaultModel = React.useCallback((id) => {
        updateState((prev) => {
            if (id === null) {
                return {
                    ...prev,
                    defaultModelId: null
                };
            }
            if (!prev.byId[id])
                return prev;
            if (prev.defaultModelId === id)
                return prev;
            return {
                ...prev,
                defaultModelId: id
            };
        });
    }, [updateState]);
    const clearModels = React.useCallback(() => {
        setValue(EMPTY_STATE);
    }, [setValue]);
    const getModel = React.useCallback((id) => state.byId[id], [state.byId]);
    const models = React.useMemo(() => state.order.map((id) => state.byId[id]).filter(Boolean), [state.byId, state.order]);
    const defaultModel = React.useMemo(() => {
        if (!state.defaultModelId)
            return null;
        return state.byId[state.defaultModelId] ?? null;
    }, [state.byId, state.defaultModelId]);
    const value = React.useMemo(() => ({
        state,
        models,
        defaultModel,
        addModel,
        updateModel,
        removeModel,
        setDefaultModel,
        clearModels,
        getModel
    }), [state, models, defaultModel, addModel, updateModel, removeModel, setDefaultModel, clearModels, getModel]);
    return React.createElement(ModelContext.Provider, { value }, children);
};
export const useModelContext = () => {
    const context = React.useContext(ModelContext);
    if (!context) {
        throw new Error('useModelContext must be used within a ModelProvider');
    }
    return context;
};
export default ModelContext;
