import { showToast, openCivitai, sendLoraToWorkflow, sendEmbeddingToWorkflow, sendModelPathToWorkflow, buildLoraSyntax, copyToClipboard } from '../../utils/uiHelpers.js';
import { modalManager } from '../../managers/ModalManager.js';
import { MODEL_TYPES } from '../../api/apiConfig.js';
import {
    scrollToTop,
    loadExampleImages
} from './showcase/ShowcaseView.js';
import { setupTabSwitching } from './ModelDescription.js';
import {
    setupModelNameEditing,
    setupBaseModelEditing,
    setupFileNameEditing,
    setupVersionNameEditing
} from './ModelMetadata.js';
import { setupTagEditMode } from './ModelTags.js';
import { getModelApiClient } from '../../api/modelApiFactory.js';
import { renderCompactTags, setupTagTooltip, formatFileSize, escapeAttribute, escapeHtml } from './utils.js';
import { renderTriggerWords, setupTriggerWordsEditMode } from './TriggerWords.js';
import { parsePresets, renderPresetTags } from './PresetTags.js';
import { initVersionsTab } from './ModelVersionsTab.js';
import { loadRecipesForModel } from './RecipeTab.js';
import { translate } from '../../utils/i18nHelpers.js';
import { showDeleteModal } from '../../utils/modalUtils.js';
import { state } from '../../state/index.js';

function getModalFilePath(fallback = '') {
    const modalElement = document.getElementById('modelModal');
    if (modalElement && modalElement.dataset && modalElement.dataset.filePath) {
        return modalElement.dataset.filePath;
    }
    return fallback;
}

const COMMERCIAL_ICON_CONFIG = [
    {
        key: 'image',
        icon: 'photo-off.svg',
        titleKey: 'modals.model.license.noImageSell',
        fallback: 'No selling generated content'
    },
    {
        key: 'rentcivit',
        icon: 'brush-off.svg',
        titleKey: 'modals.model.license.noRentCivit',
        fallback: 'No Civitai generation'
    },
    {
        key: 'rent',
        icon: 'world-off.svg',
        titleKey: 'modals.model.license.noRent',
        fallback: 'No generation services'
    },
    {
        key: 'sell',
        icon: 'shopping-cart-off.svg',
        titleKey: 'modals.model.license.noSell',
        fallback: 'No selling models'
    }
];

let navigationKeyHandler = null;
let navigationModelType = null;
let navigationInProgress = false;

function hasLicenseField(license, field) {
    return Object.prototype.hasOwnProperty.call(license || {}, field);
}

function indentMarkup(markup, spaces) {
    if (!markup) {
        return '';
    }
    const padding = ' '.repeat(spaces);
    return markup
        .split('\n')
        .map(line => (line ? padding + line : line))
        .join('\n');
}

function splitAggregateCommercialValue(value) {
    const trimmed = String(value ?? '').trim();
    const looksAggregate = trimmed.includes(',') || (trimmed.startsWith('{') && trimmed.endsWith('}'));
    if (!looksAggregate) {
        return [value];
    }

    let inner = trimmed;
    if (inner.startsWith('{') && inner.endsWith('}')) {
        inner = inner.slice(1, -1);
    }

    const parts = inner
        .split(',')
        .map(part => part.trim())
        .filter(Boolean);

    return parts.length ? parts : [value];
}

function normalizeCommercialValues(value) {
    if (!value && value !== '') {
        return ['Sell'];
    }

    if (Array.isArray(value)) {
        const flattened = [];
        value.forEach(item => {
            if (item === null || item === undefined) {
                return;
            }
            if (typeof item === 'string') {
                flattened.push(...splitAggregateCommercialValue(item));
                return;
            }
            flattened.push(String(item));
        });
        if (flattened.length > 0) {
            return flattened;
        }
        if (value.length === 0) {
            return [];
        }
    }

    if (typeof value === 'string') {
        return splitAggregateCommercialValue(value);
    }

    if (value && typeof value[Symbol.iterator] === 'function') {
        const result = [];
        for (const item of value) {
            if (item === null || item === undefined) {
                continue;
            }
            if (typeof item === 'string') {
                result.push(...splitAggregateCommercialValue(item));
                continue;
            }
            result.push(String(item));
        }
        if (result.length > 0) {
            return result;
        }
    }

    return ['Sell'];
}

function sanitiseCommercialValue(value) {
    if (!value && value !== '') {
        return '';
    }
    return String(value)
        .trim()
        .toLowerCase()
        .replace(/[\s_-]+/g, '')
        .replace(/[^a-z]/g, '');
}

function resolveCommercialRestrictions(value) {
    const normalizedValues = normalizeCommercialValues(value);
    const allowed = new Set();
    normalizedValues.forEach(item => {
        const cleaned = sanitiseCommercialValue(item);
        if (!cleaned) {
            return;
        }
        allowed.add(cleaned);
    });

    if (allowed.has('sell')) {
        allowed.add('rent');
        allowed.add('rentcivit');
        allowed.add('image');
    }
    if (allowed.has('rent')) {
        allowed.add('rentcivit');
    }

    const disallowed = [];
    COMMERCIAL_ICON_CONFIG.forEach(config => {
        if (!allowed.has(config.key)) {
            disallowed.push(config);
        }
    });
    return disallowed;
}

function createLicenseIconMarkup(icon, label) {
    const safeLabel = escapeAttribute(label);
    const iconPath = `/loras_static/images/tabler/${icon}`;
    return `<span class="license-icon" role="img" aria-label="${safeLabel}" title="${safeLabel}" style="--license-icon-image: url('${iconPath}')"></span>`;
}

function renderLicenseIcons(modelData) {
    const license = modelData?.civitai?.model;
    if (!license) {
        return '';
    }

    const icons = [];
    if (hasLicenseField(license, 'allowNoCredit') && license.allowNoCredit === false) {
        const label = translate('modals.model.license.creditRequired', {}, 'Creator credit required');
        icons.push(createLicenseIconMarkup('user-check.svg', label));
    }

    if (hasLicenseField(license, 'allowCommercialUse')) {
        const restrictions = resolveCommercialRestrictions(license.allowCommercialUse);
        restrictions.forEach(({ icon, titleKey, fallback }) => {
            const label = translate(titleKey, {}, fallback);
            icons.push(createLicenseIconMarkup(icon, label));
        });
    }

    if (hasLicenseField(license, 'allowDerivatives') && license.allowDerivatives === false) {
        const label = translate('modals.model.license.noDerivatives', {}, 'No sharing merges');
        icons.push(createLicenseIconMarkup('exchange-off.svg', label));
    }

    if (hasLicenseField(license, 'allowDifferentLicense') && license.allowDifferentLicense === false) {
        const label = translate('modals.model.license.noReLicense', {}, 'Same permissions required');
        icons.push(createLicenseIconMarkup('rotate-2.svg', label));
    }

    if (!icons.length) {
        return '';
    }

    const containerLabel = translate('modals.model.license.restrictionsLabel', {}, 'License restrictions');
    const safeContainerLabel = escapeAttribute(containerLabel);
    return `<div class="license-restrictions" aria-label="${safeContainerLabel}" role="group">
        ${icons.join('\n        ')}
    </div>`;
}

// ── Set 2 (new CivitAI-style) permission icons ──

const NEW_LICENSE_ICON_CONFIG = [
    {
        key: 'commercial',
        icon: 'currency-dollar.svg',
        allowedFn: (license) => {
            const uses = license.allowCommercialUse || [];
            return uses.includes('Image') || uses.includes('Sell');
        },
        labelAllowed: 'Commercial use allowed',
        labelDenied: 'No commercial use'
    },
    {
        key: 'genServices',
        icon: 'brush.svg',
        allowedFn: (license) => {
            const uses = license.allowCommercialUse || [];
            return uses.includes('RentCivit') || uses.includes('Rent');
        },
        labelAllowed: 'Generation services allowed',
        labelDenied: 'No generation services'
    },
    {
        key: 'credit',
        icon: 'user.svg',
        allowedFn: (license) => !!license.allowNoCredit,
        labelAllowed: 'No credit required',
        labelDenied: 'Creator credit required'
    },
    {
        key: 'derivatives',
        icon: 'git-merge.svg',
        allowedFn: (license) => !!license.allowDerivatives,
        labelAllowed: 'Merges allowed',
        labelDenied: 'No merges allowed'
    },
    {
        key: 'relicense',
        icon: 'license.svg',
        allowedFn: (license) => !!license.allowDifferentLicense,
        labelAllowed: 'Different permissions allowed on merges',
        labelDenied: 'Same permissions required on merges'
    }
];

function createNewLicenseIconMarkup(icon, allowed, label) {
    const safeLabel = escapeAttribute(label);
    const iconPath = `/loras_static/images/tabler/${icon}`;
    const stateClass = allowed ? 'allowed' : 'denied';
    return `<span class="license-icon-new ${stateClass}" role="img" aria-label="${safeLabel}" title="${safeLabel}" style="--license-icon-image: url('${iconPath}')"></span>`;
}

function renderNewLicenseIcons(modelData) {
    const license = modelData?.civitai?.model;
    if (!license) {
        return '';
    }

    const icons = [];
    NEW_LICENSE_ICON_CONFIG.forEach((config) => {
        if (config.key === 'credit' && !hasLicenseField(license, 'allowNoCredit')) {
            return;
        }
        if (config.key === 'derivatives' && !hasLicenseField(license, 'allowDerivatives')) {
            return;
        }
        if (config.key === 'relicense' && !hasLicenseField(license, 'allowDifferentLicense')) {
            return;
        }
        if ((config.key === 'commercial' || config.key === 'genServices') && !hasLicenseField(license, 'allowCommercialUse')) {
            return;
        }
        const allowed = config.allowedFn(license);
        const label = allowed ? config.labelAllowed : config.labelDenied;
        icons.push(createNewLicenseIconMarkup(config.icon, allowed, label));
    });

    if (!icons.length) {
        return '';
    }

    const containerLabel = translate('modals.model.license.restrictionsLabel', {}, 'License permissions');
    const safeContainerLabel = escapeAttribute(containerLabel);
    return `<div class="license-permissions" aria-label="${safeContainerLabel}" role="group">
        ${icons.join('\n        ')}
    </div>`;
}

/**
 * Display the model modal with the given model data
 * @param {Object} model - Model data object
 * @param {string} modelType - Type of model ('lora' or 'checkpoint')
 */
export async function showModelModal(model, modelType) {
    const modalId = 'modelModal';
    const modalTitle = model.model_name;
    cleanupNavigationShortcuts();
    detachModalHandlers(modalId);

    // Fetch complete civitai metadata
    let completeCivitaiData = model.civitai || {};
    if (model.file_path) {
        try {
            const fullMetadata = await getModelApiClient().fetchModelMetadata(model.file_path);
            completeCivitaiData = fullMetadata || model.civitai || {};
        } catch (error) {
            console.warn('Failed to fetch complete metadata, using existing data:', error);
            // Continue with existing data if fetch fails
        }
    }

    // Update model with complete civitai data
    const modelWithFullData = {
        ...model,
        civitai: completeCivitaiData
    };
    const escapedFilePathAttr = escapeAttribute(modelWithFullData.file_path || '');
    const escapedFolderPath = escapeHtml((modelWithFullData.file_path || '').replace(/[^/]+$/, '') || 'N/A');
    // De-emphasized hash display: a borderless full-width footnote line below
    // the info grid — sha256 middle-truncated (first 10 + last 6), autov3 in
    // full (12 chars); the full value is copied via data-hash.
    const modelSha256 = modelWithFullData.sha256 || '';
    const modelAutov3 = modelWithFullData.autov3 || '';
    const truncatedSha256 = modelSha256.length > 16
        ? `${modelSha256.slice(0, 10)}\u2026${modelSha256.slice(-6)}`
        : modelSha256;
    const copyHashTitle = translate('modals.model.actions.copyHash', {}, 'Copy hash');
    const hashEntries = [];
    if (modelSha256) {
        hashEntries.push(`
            <span class="hash-entry">
                <span class="hash-kind">SHA256</span>
                <span class="model-hash-value" title="${escapeAttribute(modelSha256)}">${escapeHtml(truncatedSha256)}</span>
                <button class="hash-copy-btn" data-action="copy-hash" data-hash="${escapeAttribute(modelSha256)}" title="${copyHashTitle}">
                    <i class="fas fa-copy"></i>
                </button>
            </span>`);
    }
    if (modelAutov3) {
        hashEntries.push(`
            <span class="hash-entry">
                <span class="hash-kind">AutoV3</span>
                <span class="model-hash-value" title="${escapeAttribute(modelAutov3)}">${escapeHtml(modelAutov3)}</span>
                <button class="hash-copy-btn" data-action="copy-hash" data-hash="${escapeAttribute(modelAutov3)}" title="${copyHashTitle}">
                    <i class="fas fa-copy"></i>
                </button>
            </span>`);
    }
    const hashesMarkup = modelSha256 && hashEntries.length ? `
                        <div class="hash-footnote" aria-label="${translate('modals.model.metadata.hashes', {}, 'Hashes')}">${hashEntries.join('<span class="hash-sep">·</span>')}
                        </div>` : '';
    const useNewIcons = state.global.settings.use_new_license_icons !== false;
    const licenseIcons = useNewIcons
        ? renderNewLicenseIcons(modelWithFullData)
        : renderLicenseIcons(modelWithFullData);
    const viewOnCivitaiAction = modelWithFullData.from_civitai ? `
<div class="civitai-view" title="${translate('modals.model.actions.viewOnCivitai', {}, 'View on Civitai')}" data-action="view-civitai" data-filepath="${escapedFilePathAttr}">
    <i class="fas fa-globe"></i> ${translate('modals.model.actions.viewOnCivitaiText', {}, 'View on Civitai')}
</div>`.trim() : '';
    const escapedHfUrl = modelWithFullData.hf_url ? escapeAttribute(modelWithFullData.hf_url) : '';
    const viewOnHuggingFaceAction = escapedHfUrl ? `
<div class="civitai-view" title="${translate('modals.model.actions.viewOnHuggingFace', {}, 'View on Hugging Face')}" data-action="view-huggingface" data-hf-url="${escapedHfUrl}">
    <i class="fas fa-globe"></i> ${translate('modals.model.actions.viewOnHuggingFaceText', {}, 'View on Hugging Face')}
</div>`.trim() : '';
    const creatorInfoAction = modelWithFullData.civitai?.creator ? `
<div class="creator-info" data-username="${modelWithFullData.civitai.creator.username}" data-action="view-creator" title="${translate('modals.model.actions.viewCreatorProfile', {}, 'View Creator Profile')}">
    ${modelWithFullData.civitai.creator.image ?
            `<div class="creator-avatar">
            <img src="${modelWithFullData.civitai.creator.image}" alt="${modelWithFullData.civitai.creator.username}" onerror="this.onerror=null; this.src='/loras_static/icons/user-placeholder.png';">
        </div>` :
            `<div class="creator-avatar creator-placeholder">
            <i class="fas fa-user"></i>
        </div>`
        }
    <span class="creator-username">${modelWithFullData.civitai.creator.username}</span>
</div>`.trim() : '';
    const creatorActionItems = [];
    if (viewOnCivitaiAction) {
        creatorActionItems.push(indentMarkup(viewOnCivitaiAction, 24));
    }
    if (viewOnHuggingFaceAction) {
        creatorActionItems.push(indentMarkup(viewOnHuggingFaceAction, 24));
    }
    if (creatorInfoAction) {
        creatorActionItems.push(indentMarkup(creatorInfoAction, 24));
    }
    const creatorActionsMarkup = creatorActionItems.length
        ? [
            '                    <div class="creator-actions">',
            creatorActionItems.join('\n'),
            '                    </div>'
        ].join('\n')
        : '';
    const headerActionItems = [];
    
    // Add send to ComfyUI button for all model types
    const sendToWorkflowTitle = translate('modals.model.actions.sendToWorkflow', {}, 'Send to ComfyUI');
    const sendToWorkflowButton = `
        <button class="modal-send-btn" data-action="send-to-workflow" data-model-type="${modelType}" title="${sendToWorkflowTitle}">
            <i class="fas fa-paper-plane"></i>
            <span>${translate('modals.model.actions.sendToWorkflowText', {}, 'Send to ComfyUI')}</span>
        </button>
    `.trim();
    headerActionItems.push(indentMarkup(sendToWorkflowButton, 20));
    
    if (creatorActionsMarkup) {
        headerActionItems.push(creatorActionsMarkup);
    }
    if (licenseIcons) {
        headerActionItems.push(indentMarkup(licenseIcons.trim(), 20));
    }

    // Destructive action stays last (rightmost). The license icons' auto
    // margin right-anchors the [license][delete] cluster as one group.
    const deleteModelTitle = translate('modals.model.actions.deleteModelWithShortcut', {}, 'Delete model (Del)');
    const deleteModelButton = `
        <button class="modal-delete-btn" data-action="delete-model" title="${deleteModelTitle}" aria-label="${deleteModelTitle}">
            <i class="fas fa-trash" aria-hidden="true"></i>
        </button>
    `.trim();
    headerActionItems.push(indentMarkup(deleteModelButton, 20));

    const headerActionsMarkup = headerActionItems.length
        ? [
            '                <div class="modal-header-actions">',
            headerActionItems.join('\n'),
            '                </div>'
        ].join('\n')
        : '';
    const hasUpdateAvailable = Boolean(modelWithFullData.update_available);
    const updateAvailabilityState = { hasUpdateAvailable };
    const updateBadgeTooltip = translate('modelCard.badges.updateAvailable', {}, 'Update available');

    // Prepare LoRA specific data with complete civitai data
    const escapedWords = (modelType === 'loras' || modelType === 'embeddings') && modelWithFullData.civitai?.trainedWords?.length ?
        modelWithFullData.civitai.trainedWords : [];

    // Generate model type specific content
    let typeSpecificContent;
    if (modelType === 'loras') {
        typeSpecificContent = renderLoraSpecificContent(modelWithFullData, escapedWords);
    } else if (modelType === 'embeddings') {
        typeSpecificContent = renderEmbeddingSpecificContent(modelWithFullData, escapedWords);
    } else {
        typeSpecificContent = '';
    }

    // Generate tabs based on model type
    const examplesText = translate('modals.model.tabs.examples', {}, 'Examples');
    const descriptionText = translate('modals.model.tabs.description', {}, 'Model Description');
    const recipesText = translate('modals.model.tabs.recipes', {}, 'Recipes');
    const versionsText = translate('modals.model.tabs.versions', {}, 'Versions');
    const versionsBadgeLabel = translate('modelCard.badges.update', {}, 'Update');
    const versionsTabBadge = hasUpdateAvailable
        ? `<span class="tab-badge tab-badge--update">${versionsBadgeLabel}</span>`
        : '';
    const versionsTabClasses = ['tab-btn'];
    if (hasUpdateAvailable) {
        versionsTabClasses.push('tab-btn--has-update');
    }
    const versionsTabButton = `<button class="${versionsTabClasses.join(' ')}" data-tab="versions">
                <span class="tab-label">${versionsText}</span>
                ${versionsTabBadge}
            </button>`.trim();

    const supportsRecipesTab = modelType === 'loras' || modelType === 'checkpoints';

    const tabsContent = supportsRecipesTab ?
        `<button class="tab-btn active" data-tab="showcase">${examplesText}</button>
            <button class="tab-btn" data-tab="description">${descriptionText}</button>
            ${versionsTabButton}
            <button class="tab-btn" data-tab="recipes">${recipesText}</button>` :
        `<button class="tab-btn active" data-tab="showcase">${examplesText}</button>
            <button class="tab-btn" data-tab="description">${descriptionText}</button>
            ${versionsTabButton}`;

    const loadingExampleImagesText = translate('modals.model.loading.exampleImages', {}, 'Loading example images...');
    const loadingDescriptionText = translate('modals.model.loading.description', {}, 'Loading model description...');
    const loadingRecipesText = translate('modals.model.loading.recipes', {}, 'Loading recipes...');
    const loadingExamplesText = translate('modals.model.loading.examples', {}, 'Loading examples...');

    const loadingVersionsText = translate('modals.model.loading.versions', {}, 'Loading versions...');
    // Use CivitAI modelId, or derive HF group key for HF-only models
    let civitaiModelId = modelWithFullData.civitai?.modelId || '';
    if (!civitaiModelId && modelWithFullData.hf_url) {
        const match = modelWithFullData.hf_url.match(/https?:\/\/huggingface\.co\/([^/]+\/[^/]+)/);
        if (match) {
            civitaiModelId = 'hf:' + match[1];
        }
    }
    const civitaiVersionId = modelWithFullData.civitai?.id || '';
    const navAriaLabel = translate('modals.model.navigation.label', {}, 'Model navigation');
    const previousTitle = translate('modals.model.navigation.previousWithShortcut', {}, 'Previous model (←)');
    const nextTitle = translate('modals.model.navigation.nextWithShortcut', {}, 'Next model (→)');
    const navigationControls = `
                <div class="modal-nav-controls" role="group" aria-label="${navAriaLabel}">
                    <button class="modal-nav-btn" data-action="nav-prev" title="${previousTitle}" aria-label="${previousTitle}">
                        <i class="fas fa-chevron-left" aria-hidden="true"></i>
                    </button>
                    <button class="modal-nav-btn" data-action="nav-next" title="${nextTitle}" aria-label="${nextTitle}">
                        <i class="fas fa-chevron-right" aria-hidden="true"></i>
                    </button>
                </div>`.trim();

    const tabPanesContent = supportsRecipesTab ?
        `<div id="showcase-tab" class="tab-pane active">
            <div class="example-images-loading">
                <i class="fas fa-spinner fa-spin"></i> ${loadingExampleImagesText}
            </div>
        </div>
        
        <div id="description-tab" class="tab-pane">
            <div class="model-description-container">
                <div class="model-description-loading">
                    <i class="fas fa-spinner fa-spin"></i> ${loadingDescriptionText}
                </div>
                <div class="model-description-content hidden">
                </div>
            </div>
        </div>

        <div id="versions-tab" class="tab-pane">
            <div class="model-versions-tab" data-model-id="${civitaiModelId}" data-model-type="${modelType}" data-current-version-id="${civitaiVersionId}">
                <div class="versions-loading-state">
                    <i class="fas fa-spinner fa-spin"></i> ${loadingVersionsText}
                </div>
            </div>
        </div>

        <div id="recipes-tab" class="tab-pane">
            <div class="recipes-loading">
                <i class="fas fa-spinner fa-spin"></i> ${loadingRecipesText}
            </div>
        </div>` :
        `<div id="showcase-tab" class="tab-pane active">
            <div class="recipes-loading">
                <i class="fas fa-spinner fa-spin"></i> ${loadingExamplesText}
            </div>
        </div>
        
        <div id="description-tab" class="tab-pane">
            <div class="model-description-container">
                <div class="model-description-loading">
                    <i class="fas fa-spinner fa-spin"></i> ${loadingDescriptionText}
                </div>
                <div class="model-description-content hidden">
                </div>
            </div>
        </div>

        <div id="versions-tab" class="tab-pane">
            <div class="model-versions-tab" data-model-id="${civitaiModelId}" data-model-type="${modelType}" data-current-version-id="${civitaiVersionId}">
                <div class="versions-loading-state">
                    <i class="fas fa-spinner fa-spin"></i> ${loadingVersionsText}
                </div>
            </div>
        </div>`;

    const content = `
        <div class="modal-content">
            <button class="close" onclick="modalManager.closeModal('${modalId}')">&times;</button>
            <header class="modal-header">
                <div class="modal-header-row">
                    <div class="model-name-header">
                        <h2 class="model-name-content">${modalTitle}</h2>
                        <button class="edit-model-name-btn" title="${translate('modals.model.actions.editModelName', {}, 'Edit model name')}">
                            <i class="fas fa-pencil-alt"></i>
                        </button>
                    </div>

                    ${navigationControls}
                </div>

                ${headerActionsMarkup}

                ${renderCompactTags(modelWithFullData.tags || [], modelWithFullData.file_path)}
            </header>

            <div class="modal-body">
                <div class="info-section">
                    <div class="info-grid">
                        <div class="info-item">
                            <label>${translate('modals.model.metadata.version', {}, 'Version')}</label>
                            <div class="version-name-wrapper">
                                <span class="version-name-content">${modelWithFullData.civitai?.name || 'N/A'}</span>
                                <button class="edit-version-name-btn" title="${translate('modals.model.actions.editVersionName', {}, 'Edit version name')}">
                                    <i class="fas fa-pencil-alt"></i>
                                </button>
                            </div>
                        </div>
                        <div class="info-item">
                            <label>${translate('modals.model.metadata.fileName', {}, 'File Name')}</label>
                            <div class="file-name-wrapper">
                                <span id="file-name" class="file-name-content">${modelWithFullData.file_name || 'N/A'}</span>
                                <button class="edit-file-name-btn" title="${translate('modals.model.actions.editFileName', {}, 'Edit file name')}">
                                    <i class="fas fa-pencil-alt"></i>
                                </button>
                            </div>
                        </div>
                        <div class="info-item">
                            <div class="location-wrapper">
                                <label>${translate('modals.model.metadata.location', {}, 'Location')}</label>
                                <span class="file-path" title="${translate('modals.model.actions.openFileLocation', {}, 'Open file location')}"
                                    data-action="open-file-location"
                                    data-filepath="${escapedFilePathAttr}">
                                    ${escapedFolderPath}
                                </span>
                            </div>
                        </div>
                        <div class="info-item base-size">
                            <div class="base-wrapper">
                                <label>${translate('modals.model.metadata.baseModel', {}, 'Base Model')}</label>
                                <div class="base-model-display">
                                    <span class="base-model-content">${modelWithFullData.base_model || translate('modals.model.metadata.unknown', {}, 'Unknown')}</span>
                                    <button class="edit-base-model-btn" title="${translate('modals.model.actions.editBaseModel', {}, 'Edit base model')}">
                                        <i class="fas fa-pencil-alt"></i>
                                    </button>
                                </div>
                            </div>
                            <div class="size-wrapper">
                                <label>${translate('modals.model.metadata.size', {}, 'Size')}</label>
                                <span>${formatFileSize(modelWithFullData.file_size)}</span>
                            </div>
                        </div>
                        ${hashesMarkup}
                        ${typeSpecificContent}
                        <div class="info-item notes">
                            <div class="notes-header">
                                <label>${translate('modals.model.metadata.additionalNotes', {}, 'Additional Notes')} <i class="fas fa-info-circle notes-hint" title="${translate('modals.model.metadata.notesHint', {}, 'Press Enter to save, Shift+Enter for new line')}"></i></label>
                                <button class="notes-toggle-btn" style="display:none" title="${translate('modals.model.notes.showMore', {}, 'Show more')}">
                                    <i class="fas fa-chevron-down"></i>
                                </button>
                            </div>
                            <div class="editable-field">
                                <div class="notes-content" contenteditable="true" spellcheck="false">${modelWithFullData.notes || translate('modals.model.metadata.addNotesPlaceholder', {}, 'Add your notes here...')}</div>
                            </div>
                        </div>
                        <div class="info-item full-width">
                            <label>${translate('modals.model.metadata.aboutThisVersion', {}, 'About this version')}</label>
                            <div class="description-text">${modelWithFullData.civitai?.description || 'N/A'}</div>
                        </div>
                    </div>
                </div>

                <div class="showcase-section" data-model-hash="${modelWithFullData.sha256 || ''}" data-model-name="${escapeAttribute(modelWithFullData.file_name || modelWithFullData.model_name || '')}" data-model-type="${modelType}" data-filepath="${escapedFilePathAttr}">
                    <div class="showcase-tabs">
                        ${tabsContent}
                    </div>
                    
                    <div class="tab-content">
                        ${tabPanesContent}
                    </div>
                    
                    <button class="back-to-top" data-action="scroll-to-top">
                        <i class="fas fa-arrow-up"></i>
                    </button>
                </div>
            </div>
        </div>
    `;

    function updateVersionsTabBadge(hasUpdate) {
        const modalElement = document.getElementById(modalId);
        if (!modalElement) return;

        const tabButton = modalElement.querySelector('.tab-btn[data-tab="versions"]');
        if (!tabButton) return;

        tabButton.classList.toggle('tab-btn--has-update', hasUpdate);

        let badge = tabButton.querySelector('.tab-badge--update');
        if (hasUpdate) {
            if (!badge) {
                badge = document.createElement('span');
                badge.className = 'tab-badge tab-badge--update';
                badge.textContent = versionsBadgeLabel;
                badge.title = updateBadgeTooltip;
                tabButton.appendChild(badge);
            } else {
                badge.textContent = versionsBadgeLabel;
                badge.title = updateBadgeTooltip;
            }
        } else if (badge) {
            badge.remove();
        }
    }

    function updateCardUpdateAvailability(hasUpdate) {
        const filePath = modelWithFullData.file_path;
        if (!filePath) return;

        let updatedViaScroller = false;
        if (state.virtualScroller?.updateSingleItem) {
            updatedViaScroller = state.virtualScroller.updateSingleItem(filePath, {
                update_available: hasUpdate,
            });
        }

        if (updatedViaScroller) {
            return;
        }

        const escapedPath = window.CSS && typeof window.CSS.escape === 'function'
            ? window.CSS.escape(filePath)
            : filePath.replace(/["\\]/g, '\\$&');
        const card = document.querySelector(`.model-card[data-filepath="${escapedPath}"]`);
        if (!card) return;

        card.dataset.update_available = hasUpdate ? 'true' : 'false';
        card.classList.toggle('has-update', hasUpdate);

        const headerInfo = card.querySelector('.card-header-info');
        if (!headerInfo) return;

        let badge = headerInfo.querySelector('.model-update-badge');
        if (hasUpdate) {
            if (!badge) {
                badge = document.createElement('span');
                badge.className = 'model-update-badge';
                badge.title = updateBadgeTooltip;
                badge.textContent = versionsBadgeLabel;
                headerInfo.appendChild(badge);
            }
        } else if (badge) {
            badge.remove();
        }
    }

    function handleUpdateStatusChange(hasUpdate) {
        if (updateAvailabilityState.hasUpdateAvailable === hasUpdate) {
            return;
        }
        updateAvailabilityState.hasUpdateAvailable = hasUpdate;
        updateVersionsTabBadge(hasUpdate);
        updateCardUpdateAvailability(hasUpdate);
    }

    const onCloseCallback = function () {
        // Clean up all handlers when modal closes for LoRA
        const modalElement = document.getElementById(modalId);
        if (modalElement && modalElement._clickHandler) {
            modalElement.removeEventListener('click', modalElement._clickHandler);
            delete modalElement._clickHandler;
        }
        cleanupNavigationShortcuts();
    };

    modalManager.showModal(modalId, content, null, onCloseCallback);
    const activeModalElement = document.getElementById(modalId);
    if (activeModalElement) {
        activeModalElement.dataset.filePath = modelWithFullData.file_path || '';
        // Store usage_tips for LoRA models
        if (modelType === 'loras' && modelWithFullData.usage_tips) {
            activeModalElement.dataset.usageTips = modelWithFullData.usage_tips;
        }
        // Store sub_type for checkpoint models
        if (modelType === 'checkpoints' && modelWithFullData.sub_type) {
            activeModalElement.dataset.subType = modelWithFullData.sub_type;
        }
        // Store folder for embedding models
        if (modelType === 'embeddings' && modelWithFullData.folder) {
            activeModalElement.dataset.folder = modelWithFullData.folder;
        }
        // Show the back-to-top button once the modal content is scrolled
        const modalContent = activeModalElement.querySelector('.modal-content');
        const backToTopBtn = activeModalElement.querySelector('.back-to-top');
        if (modalContent && backToTopBtn) {
            modalContent.addEventListener('scroll', () => {
                backToTopBtn.classList.toggle('visible', modalContent.scrollTop > 300);
            });
        }
    }
    updateVersionsTabBadge(updateAvailabilityState.hasUpdateAvailable);
    const versionsTabController = initVersionsTab({
        modalId,
        modelType,
        modelId: civitaiModelId,
        currentVersionId: civitaiVersionId,
        currentBaseModel: modelWithFullData.base_model,
        modelName: model.model_name,
        onUpdateStatusChange: handleUpdateStatusChange,
    });
    setupEditableFields(modelWithFullData.file_path, modelType);
    setupTabSwitching({
        onTabChange: async (tab) => {
            if (tab === 'versions') {
                await versionsTabController.load();
            }
        },
    });
    versionsTabController.load({ eager: true });
    setupTagTooltip();
    setupTagEditMode(modelType);
    setupModelNameEditing(modelWithFullData.file_path);
    setupVersionNameEditing(modelWithFullData.file_path);
    setupBaseModelEditing(modelWithFullData.file_path);
    setupFileNameEditing(modelWithFullData.file_path);
    setupEventHandlers(modelWithFullData.file_path, modelType);
    setupNavigationShortcuts(modelType);
    updateNavigationControls();

    // Model-specific setup
    if (modelType === 'loras' || modelType === 'embeddings') {
        setupTriggerWordsEditMode();
    }

    if (modelType === 'loras') {
        loadRecipesForModel({
            modelKind: 'lora',
            displayName: modelWithFullData.model_name,
            sha256: modelWithFullData.sha256,
        });
    } else if (modelType === 'checkpoints') {
        loadRecipesForModel({
            modelKind: 'checkpoint',
            displayName: modelWithFullData.model_name,
            sha256: modelWithFullData.sha256,
        });
    }

    // Load example images asynchronously - merge regular and custom images
    const regularImages = modelWithFullData.civitai?.images || [];
    const customImages = modelWithFullData.civitai?.customImages || [];
    // Combine images - regular images first, then custom images
    const allImages = [...regularImages, ...customImages];
    loadExampleImages(allImages, modelWithFullData.sha256, modelWithFullData.preview_url || '');
}

function renderLoraSpecificContent(lora, escapedWords) {
    return `
        <div class="info-item usage-tips">
            <label>${translate('modals.model.metadata.usageTips', {}, 'Usage Tips')}</label>
            <div class="editable-field">
                <div class="preset-controls">
                    <select id="preset-selector">
                        <option value="">${translate('modals.model.usageTips.addPresetParameter', {}, 'Add preset parameter...')}</option>
                        <option value="strength_min">${translate('modals.model.usageTips.strengthMin', {}, 'Strength Min')}</option>
                        <option value="strength_max">${translate('modals.model.usageTips.strengthMax', {}, 'Strength Max')}</option>
                        <option value="strength_range">${translate('modals.model.usageTips.strengthRange', {}, 'Strength Range')}</option>
                        <option value="strength">${translate('modals.model.usageTips.strength', {}, 'Strength')}</option>
                        <option value="clip_strength">${translate('modals.model.usageTips.clipStrength', {}, 'Clip Strength')}</option>
                        <option value="clip_skip">${translate('modals.model.usageTips.clipSkip', {}, 'Clip Skip')}</option>
                    </select>
                    <input type="number" id="preset-value" step="0.01" placeholder="${translate('modals.model.usageTips.valuePlaceholder', {}, 'Value')}" style="display:none;">
                    <button class="add-preset-btn">${translate('modals.model.usageTips.add', {}, 'Add')}</button>
                </div>
                <div class="preset-tags">
                    ${renderPresetTags(parsePresets(lora.usage_tips))}
                </div>
            </div>
        </div>
        ${renderTriggerWords(escapedWords, lora.file_path)}
    `;
}

function renderEmbeddingSpecificContent(embedding, escapedWords) {
    return `${renderTriggerWords(escapedWords, embedding.file_path)}`;
}

function detachModalHandlers(modalId) {
    const modalElement = document.getElementById(modalId);
    if (modalElement && modalElement._clickHandler) {
        modalElement.removeEventListener('click', modalElement._clickHandler);
        delete modalElement._clickHandler;
    }
}

/**
 * Sets up event handlers using event delegation for LoRA modal
 * @param {string} filePath - Path to the model file
 * @param {string} modelType - Current model type
 */
function setupEventHandlers(filePath, modelType) {
    const modalElement = document.getElementById('modelModal');

    // Remove existing event listeners first
    modalElement.removeEventListener('click', handleModalClick);

    // Create and store the handler function
    function handleModalClick(event) {
        const target = event.target.closest('[data-action]');
        if (!target) return;

        const action = target.dataset.action;

        switch (action) {
            case 'close-modal':
                modalManager.closeModal('modelModal');
                break;
            case 'scroll-to-top':
                scrollToTop(target);
                break;
            case 'view-civitai':
                openCivitai(target.dataset.filepath);
                break;
            case 'view-huggingface':
                if (target.dataset.hfUrl) {
                    window.open(target.dataset.hfUrl, '_blank', 'noopener,noreferrer');
                }
                break;
            case 'view-creator':
                const username = target.dataset.username;
                if (username) {
                    const host = state.global.settings.civitai_host || 'civitai.com';
                    window.open(`https://${host}/user/${username}`, '_blank');
                }
                break;
            case 'open-file-location':
                const filePath = target.dataset.filepath || getModalFilePath();
                if (filePath) {
                    openFileLocation(filePath);
                }
                break;
            case 'nav-prev':
                handleDirectionalNavigation('prev', modelType);
                break;
            case 'nav-next':
                handleDirectionalNavigation('next', modelType);
                break;
            case 'send-to-workflow':
                handleSendToWorkflow(target, modelType);
                break;
            case 'delete-model':
                handleDeleteModel();
                break;
            case 'copy-hash':
                if (target.dataset.hash) {
                    copyToClipboard(target.dataset.hash, 'Hash copied to clipboard');
                }
                break;
        }
    }

    // Add the event listener with the named function
    modalElement.addEventListener('click', handleModalClick);

    // Store reference to the handler on the element for potential cleanup
    modalElement._clickHandler = handleModalClick;
}

/**
 * Set up editable fields (notes and usage tips) in the model modal
 * @param {string} filePath - The full file path of the model
 * @param {string} modelType - Type of model ('loras' or 'checkpoints' or 'embeddings')
 */
function setupEditableFields(filePath, modelType) {
    const editableFields = document.querySelectorAll('.editable-field [contenteditable]');

    editableFields.forEach(field => {
        field.addEventListener('focus', function () {
            if (this.textContent === 'Add your notes here...') {
                this.textContent = '';
            }
        });

        field.addEventListener('blur', function () {
            if (this.textContent.trim() === '') {
                if (this.classList.contains('notes-content')) {
                    this.textContent = 'Add your notes here...';
                }
            }
        });
    });

    // Add keydown event listeners for notes
    const notesContent = document.querySelector('.notes-content');
    if (notesContent) {
        notesContent.addEventListener('keydown', async function (e) {
            if (e.key === 'Enter') {
                if (e.shiftKey) {
                    // Allow shift+enter for new line
                    return;
                }
                e.preventDefault();
                await saveNotes();
            }
        });
    }

    // Setup adaptive expand/collapse for notes
    setupNotesExpand();

    // LoRA specific field setup
    if (modelType === 'loras') {
        setupLoraSpecificFields(filePath);
    }
}

/**
 * Adaptive expand/collapse for the Additional Notes section.
 * Measures content height synchronously after render (before first paint,
 * so no visual flash). If notes fit within ~4 lines, no toggle is shown.
 * If they exceed the threshold, the field collapses with a gradient fade
 * and a "Show more" button appears.
 */
function setupNotesExpand() {
    const notesContainer = document.querySelector('.info-item.notes');
    if (!notesContainer) return;

    const notesField = notesContainer.querySelector('.editable-field');
    const notesContent = notesContainer.querySelector('.notes-content');
    const toggleBtn = notesContainer.querySelector('.notes-toggle-btn');

    if (!notesField || !notesContent || !toggleBtn) return;

    const placeholderText = translate('modals.model.metadata.addNotesPlaceholder', {}, 'Add your notes here...');
    const content = notesContent.textContent || '';
    const isEmpty = !content.trim() || content === placeholderText;

    if (isEmpty) {
        return;
    }

    // CSS default has no constraints, so scrollHeight reflects full content
    const contentHeight = notesContent.scrollHeight;
    const collapsedThreshold = 95; // ~4 lines

    if (contentHeight <= collapsedThreshold) {
        return;
    }

    // Long content — collapse and show toggle
    notesField.classList.add('collapsed');
    toggleBtn.style.display = 'inline-flex';
    toggleBtn.title = translate('modals.model.notes.showMore', {}, 'Show more');

    const toggleIcon = toggleBtn.querySelector('i');

    toggleBtn.addEventListener('click', function onClick() {
        const isCollapsed = notesField.classList.contains('collapsed');
        if (isCollapsed) {
            notesField.classList.remove('collapsed');
            toggleBtn.title = translate('modals.model.notes.showLess', {}, 'Show less');
            toggleIcon.className = 'fas fa-chevron-up';
            notesField.scrollIntoView({ behavior: 'smooth', block: 'nearest' });
        } else {
            notesField.classList.add('collapsed');
            toggleBtn.title = translate('modals.model.notes.showMore', {}, 'Show more');
            toggleIcon.className = 'fas fa-chevron-down';
        }
    });
}

function setupLoraSpecificFields(filePath) {
    const presetSelector = document.getElementById('preset-selector');
    const presetValue = document.getElementById('preset-value');
    const addPresetBtn = document.querySelector('.add-preset-btn');
    const presetTags = document.querySelector('.preset-tags');
    const resolveFilePath = () => getModalFilePath(filePath);

    if (!presetSelector || !presetValue || !addPresetBtn || !presetTags) return;

    presetSelector.addEventListener('change', function () {
        const selected = this.value;
        if (selected) {
            presetValue.style.display = 'inline-block';
            if (selected === 'strength_range') {
                presetValue.type = 'text';
                presetValue.placeholder = 'e.g. 0.8-1.2';
                presetValue.removeAttribute('min');
                presetValue.removeAttribute('max');
                presetValue.removeAttribute('step');
            } else {
                presetValue.type = 'number';
                presetValue.placeholder = translate('modals.model.usageTips.valuePlaceholder', {}, 'Value');
                presetValue.min = selected.includes('strength') ? -10 : 0;
                presetValue.max = selected.includes('strength') ? 10 : 10;
                presetValue.step = 0.5;
                if (selected === 'clip_skip') {
                    presetValue.step = 1;
                }
            }
            // Add auto-focus
            setTimeout(() => presetValue.focus(), 0);
        } else {
            presetValue.style.display = 'none';
        }
    });

    addPresetBtn.addEventListener('click', async function () {
        const key = presetSelector.value;
        const value = presetValue.value;

        if (!key || !value) return;

        const currentPath = resolveFilePath();
        if (!currentPath) return;
        const escapedCurrentPath = window.CSS && typeof window.CSS.escape === 'function'
            ? window.CSS.escape(currentPath)
            : currentPath.replace(/["\\]/g, '\\$&');
        const escapedFilePath = window.CSS && typeof window.CSS.escape === 'function'
            ? window.CSS.escape(filePath)
            : filePath.replace(/["\\]/g, '\\$&');
        const loraCard = document.querySelector(`.model-card[data-filepath="${escapedCurrentPath}"]`) ||
            document.querySelector(`.model-card[data-filepath="${escapedFilePath}"]`);
        const currentPresets = parsePresets(loraCard?.dataset.usage_tips);

        if (key === 'strength_range') {
            const rangeMatch = value.match(/^(-?\d*\.?\d+)\s*[-~]\s*(-?\d*\.?\d+)$/);
            if (rangeMatch) {
                currentPresets['strength_min'] = parseFloat(rangeMatch[1]);
                currentPresets['strength_max'] = parseFloat(rangeMatch[2]);
            } else {
                showToast('modals.model.usageTips.invalidRange', {}, 'error', 'Invalid range format. Use x.x-y.y');
                return;
            }
        } else {
            currentPresets[key] = parseFloat(value);
        }
        const newPresetsJson = JSON.stringify(currentPresets);

        await getModelApiClient().saveModelMetadata(currentPath, { usage_tips: newPresetsJson });

        presetTags.innerHTML = renderPresetTags(currentPresets);

        presetSelector.value = '';
        presetValue.value = '';
        presetValue.style.display = 'none';
    });

    // Add keydown event for preset value
    presetValue.addEventListener('keydown', function (e) {
        if (e.key === 'Enter') {
            e.preventDefault();
            addPresetBtn.click();
        }
    });
}

/**
 * Save model notes using the current modal file path.
 */
async function saveNotes() {
    const filePath = getModalFilePath();
    if (!filePath) {
        return;
    }
    const content = document.querySelector('.notes-content').textContent;
    try {
        await getModelApiClient().saveModelMetadata(filePath, { notes: content });

        showToast('modals.model.notes.saved', {}, 'success');
    } catch (error) {
        showToast('modals.model.notes.saveFailed', {}, 'error');
    }
}

function shouldIgnoreNavigationKey(event) {
    const target = event.target;
    if (!target) return false;
    const tagName = target.tagName ? target.tagName.toLowerCase() : '';
    return target.isContentEditable || ['input', 'textarea', 'select', 'button'].includes(tagName);
}

function updateNavigationControls() {
    const modalElement = document.getElementById('modelModal');
    if (!modalElement) return;

    const prevBtn = modalElement.querySelector('[data-action="nav-prev"]');
    const nextBtn = modalElement.querySelector('[data-action="nav-next"]');
    if (!prevBtn || !nextBtn) return;

    const scroller = state.virtualScroller;
    if (!scroller || typeof scroller.getNavigationState !== 'function') {
        prevBtn.disabled = true;
        nextBtn.disabled = true;
        return;
    }

    const { hasPrev, hasNext } = scroller.getNavigationState(modalElement.dataset.filePath || '');
    prevBtn.disabled = navigationInProgress || !hasPrev;
    nextBtn.disabled = navigationInProgress || !hasNext;
}

function cleanupNavigationShortcuts() {
    if (navigationKeyHandler) {
        document.removeEventListener('keydown', navigationKeyHandler);
        navigationKeyHandler = null;
    }
    navigationModelType = null;
    navigationInProgress = false;
}

function setupNavigationShortcuts(modelType) {
    const modalElement = document.getElementById('modelModal');
    if (!modalElement) return;

    cleanupNavigationShortcuts();
    navigationModelType = modelType;

    navigationKeyHandler = (event) => {
        if (shouldIgnoreNavigationKey(event)) return;

        if (event.key === 'ArrowLeft') {
            event.preventDefault();
            handleDirectionalNavigation('prev', navigationModelType);
        } else if (event.key === 'ArrowRight') {
            event.preventDefault();
            handleDirectionalNavigation('next', navigationModelType);
        } else if (event.key === 'Delete') {
            event.preventDefault();
            handleDeleteModel();
        }
    };

    document.addEventListener('keydown', navigationKeyHandler);
}

/**
 * Open the shared delete confirmation for the model currently shown in the
 * modal. Showing the delete modal replaces this modal (ModalManager only
 * keeps one modal open), which also unregisters these shortcuts.
 */
function handleDeleteModel() {
    const filePath = getModalFilePath();
    if (!filePath) return;
    showDeleteModal(filePath);
}

async function handleDirectionalNavigation(direction, modelType) {
    if (navigationInProgress) return;

    const modalElement = document.getElementById('modelModal');
    const scroller = state.virtualScroller;
    const filePath = modalElement?.dataset?.filePath || '';

    if (!modalElement || !filePath || !scroller || typeof scroller.getAdjacentItemByFilePath !== 'function') {
        return;
    }

    navigationInProgress = true;
    updateNavigationControls();

    try {
        const adjacent = await scroller.getAdjacentItemByFilePath(filePath, direction);
        if (!adjacent || !adjacent.item) {
            const toastKey = direction === 'prev' ? 'modals.model.navigation.noPrevious' : 'modals.model.navigation.noNext';
            const toastFallback = direction === 'prev' ? 'No previous model available' : 'No next model available';
            showToast(toastKey, {}, 'info', toastFallback);
            return;
        }

        navigationModelType = modelType || navigationModelType;
        await showModelModal(adjacent.item, navigationModelType || modelType);
    } finally {
        navigationInProgress = false;
        updateNavigationControls();
    }
}

/**
 * Call backend to open file location and select the file
 * @param {string} filePath
 */
async function openFileLocation(filePath) {
    try {
        const resp = await fetch('/api/lm/open-file-location', {
            method: 'POST',
            headers: { 'Content-Type': 'application/json' },
            body: JSON.stringify({ 'file_path': filePath })
        });
        if (!resp.ok) throw new Error('Failed to open file location');

        const data = await resp.json();

        if (data.mode === 'clipboard' && data.path) {
            try {
                await navigator.clipboard.writeText(data.path);
                showToast('modals.model.openFileLocation.copied', { path: data.path }, 'success');
            } catch (clipboardErr) {
                console.warn('Clipboard API not available:', clipboardErr);
                showToast('modals.model.openFileLocation.clipboardFallback', { path: data.path }, 'info');
            }
        } else {
            showToast('modals.model.openFileLocation.success', {}, 'success');
        }
    } catch (err) {
        showToast('modals.model.openFileLocation.failed', {}, 'error');
    }
}

async function handleSendToWorkflow(target, modelType) {
    const filePath = getModalFilePath();
    if (!filePath) {
        showToast('modals.model.sendToWorkflow.noFilePath', {}, 'error');
        return;
    }

    // Get the current model data from the modal
    const modalElement = document.getElementById('modelModal');
    const currentFileName = modalElement?.querySelector('#file-name')?.textContent || '';
    
    if (modelType === 'loras') {
        // For LoRA: Build syntax from usage tips and send
        const usageTipsData = modalElement?.dataset?.usageTips;
        const usageTips = usageTipsData ? JSON.parse(usageTipsData) : {};
        const loraSyntax = buildLoraSyntax(currentFileName, usageTips);
        await sendLoraToWorkflow(loraSyntax, false, 'lora');
    } else if (modelType === 'checkpoints') {
        // For Checkpoint: Send model path
        const subtype = (modalElement?.dataset?.subType || 'checkpoint').toLowerCase();
        const isDiffusionModel = subtype === 'diffusion_model';
        const widgetName = isDiffusionModel ? 'unet_name' : 'ckpt_name';
        const actionTypeText = translate(
            isDiffusionModel ? 'uiHelpers.nodeSelector.diffusionModel' : 'uiHelpers.nodeSelector.checkpoint',
            {},
            isDiffusionModel ? 'Diffusion Model' : 'Checkpoint'
        );
        const successMessage = translate(
            'uiHelpers.workflow.modelUpdated',
            {},
            'Model updated in workflow'
        );
        const failureMessage = translate(
            'uiHelpers.workflow.modelFailed',
            {},
            'Failed to update model node'
        );
        const missingNodesMessage = translate(
            'uiHelpers.workflow.noMatchingNodes',
            {},
            'No compatible nodes available in the current workflow'
        );
        const missingTargetMessage = translate(
            'uiHelpers.workflow.noTargetNodeSelected',
            {},
            'No target node selected'
        );

        await sendModelPathToWorkflow(filePath, {
            widgetName,
            collectionType: MODEL_TYPES.CHECKPOINT,
            actionTypeText,
            successMessage,
            failureMessage,
            missingNodesMessage,
            missingTargetMessage,
        });
    } else if (modelType === 'embeddings') {
        const folder = modalElement?.dataset?.folder || '';
        const name = currentFileName.replace(/\.[^.]+$/, '');
        const embeddingCode = folder ? `embedding:${folder}/${name}` : `embedding:${name}`;
        await sendEmbeddingToWorkflow(embeddingCode);
    }
}

// Export the model modal API
const modelModal = {
    show: showModelModal,
    scrollToTop
};

export { modelModal };
