import { showToast } from '../../utils/uiHelpers.js';
import { translate } from '../../utils/i18nHelpers.js';
import { getModelApiClient } from '../../api/modelApiFactory.js';
import { MODEL_TYPES } from '../../api/apiConfig.js';
import { getStorageItem } from '../../utils/storageHelpers.js';
import { state } from '../../state/index.js';

export class DownloadManager {
    constructor(importManager) {
        this.importManager = importManager;
    }

    async saveRecipe(skipDownload = false) {
        // Check if we're in download-only mode (for existing recipe)
        const isDownloadOnly = !!this.importManager.recipeId;

        if (!isDownloadOnly && !this.importManager.recipeName) {
            showToast('toast.recipes.enterRecipeName', {}, 'error');
            return;
        }

        console.log(
            `[RecipeImport] Saving recipe "${this.importManager.recipeName}" (download-only=${isDownloadOnly}, skipDownload=${skipDownload})`
        );

        try {
            // Show progress indicator
            const loadingMessage = skipDownload 
                ? translate('recipes.controls.import.savingRecipe', {}, 'Saving recipe...')
                : (isDownloadOnly ? translate('recipes.controls.import.downloadingLoras', {}, 'Downloading LoRAs...') : translate('recipes.controls.import.savingRecipe', {}, 'Saving recipe...'));
            this.importManager.loadingManager.showSimpleLoading(loadingMessage);

            // Only send the complete recipe to save if not in download-only mode
            if (!isDownloadOnly) {
                // Create FormData object for saving recipe
                const formData = new FormData();

                // Add image data - depends on import mode
                if (this.importManager.recipeImage) {
                    // Direct upload
                    formData.append('image', this.importManager.recipeImage);
                } else if (this.importManager.recipeData && this.importManager.recipeData.image_base64) {
                    // URL mode with base64 data
                    formData.append('image_base64', this.importManager.recipeData.image_base64);
                } else if (this.importManager.importMode === 'url') {
                    // Fallback for URL mode - tell backend to fetch the image again
                    const urlInput = document.getElementById('imageUrlInput');
                    if (urlInput && urlInput.value) {
                        formData.append('image_url', urlInput.value);
                    } else {
                        throw new Error('No image data available');
                    }
                } else {
                    throw new Error('No image data available');
                }

                formData.append('name', this.importManager.recipeName);
                formData.append('tags', JSON.stringify(this.importManager.recipeTags));

                // Prepare complete metadata including generation parameters
                const completeMetadata = {
                    base_model: this.importManager.recipeData.base_model || "",
                    loras: this.importManager.recipeData.loras || [],
                    gen_params: this.importManager.recipeData.gen_params || {},
                    raw_metadata: this.importManager.recipeData.raw_metadata || {},
                };

                // Preserve preview_nsfw_level from analysis so the saved
                // recipe applies the correct NSFW blur on the preview image.
                const nsfwLevel = this.importManager.recipeData.preview_nsfw_level;
                if (nsfwLevel !== undefined && nsfwLevel !== null) {
                    completeMetadata.preview_nsfw_level = nsfwLevel;
                }

                const checkpointMetadata =
                    this.importManager.recipeData.checkpoint ||
                    this.importManager.recipeData.model ||
                    (this.importManager.recipeData.gen_params || {}).checkpoint;

                if (checkpointMetadata && typeof checkpointMetadata === 'object') {
                    completeMetadata.checkpoint = checkpointMetadata;
                }

                if (this.importManager.recipeData && this.importManager.recipeData.extension) {
                    formData.append('extension', this.importManager.recipeData.extension);
                }

                // Add source_path to metadata to track where the recipe was imported from
                if (this.importManager.importMode === 'url') {
                    const urlInput = document.getElementById('imageUrlInput');
                    if (urlInput && urlInput.value) {
                        completeMetadata.source_path = urlInput.value;
                    }
                }

                formData.append('metadata', JSON.stringify(completeMetadata));

                // Send save request
                const response = await fetch('/api/lm/recipes/save', {
                    method: 'POST',
                    body: formData
                });

                const result = await response.json();

                if (!result.success) {
                    // Handle save error
                    console.error("Failed to save recipe:", result.error);
                    console.log('[RecipeImport] Save failed; closing import modal.');
                    showToast('toast.recipes.recipeSaveFailed', { error: result.error }, 'error');
                    // Close modal
                    modalManager.closeModal('importModal');
                    return;
                }
            }

            // Check if we need to download LoRAs (skip if skipDownload is true)
            let failedDownloads = 0;
            if (!skipDownload && this.importManager.downloadableLoRAs && this.importManager.downloadableLoRAs.length > 0) {
                console.log(`[RecipeImport] Downloading ${this.importManager.downloadableLoRAs.length} missing LoRA(s)...`);
                await this.downloadMissingLoras();
            }

            // Show success message
            if (isDownloadOnly) {
                if (skipDownload) {
                    showToast('toast.recipes.recipeSaved', {}, 'success');
                } else if (failedDownloads === 0) {
                    showToast('toast.loras.downloadSuccessful', {}, 'success');
                }
            } else {
                showToast('toast.recipes.nameSaved', { name: this.importManager.recipeName }, 'success');
            }

            modalManager.closeModal('importModal');
            console.log(`[RecipeImport] Recipe "${this.importManager.recipeName}" saved successfully.`);

            if (isDownloadOnly && state.virtualScroller) {
                const recipeId = this.importManager.recipeId;
                try {
                    const detailRes = await fetch(`/api/lm/recipe/${encodeURIComponent(recipeId)}`);
                    if (detailRes.ok) {
                        const updated = await detailRes.json();
                        state.virtualScroller.updateSingleItem(updated.file_path, updated);
                    } else {
                        throw new Error(`API returned ${detailRes.status}`);
                    }
                } catch (e) {
                    console.warn('Failed to update recipe card in-place, falling back to reload:', e);
                    await window.recipeManager.loadRecipes({ resetPage: true, preserveScroll: true });
                }
            } else {
                window.recipeManager.loadRecipes({ resetPage: true, preserveScroll: true });
            }

        } catch (error) {
            console.error('Error:', error);
            showToast('toast.recipes.processingError', { message: error.message }, 'error');
        } finally {
            this.importManager.loadingManager.hide();
        }
    }

    async downloadMissingLoras() {
        // For download, we need to validate the target path
        const loraRoot = document.getElementById('importLoraRoot')?.value;
        if (!loraRoot) {
            throw new Error(translate('recipes.controls.import.errors.selectLoraRoot', {}, 'Please select a LoRA root directory'));
        }

        // Build target path
        let targetPath = '';
        if (this.importManager.selectedFolder) {
            targetPath = this.importManager.selectedFolder;
        }

        // Generate a unique ID for this batch download
        const batchDownloadId = Date.now().toString();

        // Set up WebSocket for progress updates
        const wsProtocol = window.location.protocol === 'https:' ? 'wss://' : 'ws://';
        const ws = new WebSocket(`${wsProtocol}${window.location.host}/ws/download-progress?id=${batchDownloadId}`);

        // Show enhanced loading with progress details for multiple items
        const updateProgress = this.importManager.loadingManager.showDownloadProgress(
            this.importManager.downloadableLoRAs.length
        );

        let completedDownloads = 0;
        let failedDownloads = 0;
        let accessFailures = 0;
        let currentLoraProgress = 0;
        let cancelled = false;

        this.importManager.loadingManager.showCancelButton(async () => {
            if (cancelled) return;
            cancelled = true;
            try {
                const loraClient = getModelApiClient(MODEL_TYPES.LORA);
                await loraClient.cancelDownload(batchDownloadId);
            } catch (e) {
                console.error('Cancel request failed:', e);
            }
        });

        // Set up progress tracking for current download
        ws.onmessage = (event) => {
            const data = JSON.parse(event.data);

            // Handle download ID confirmation
            if (data.type === 'download_id') {
                console.log(`Connected to batch download progress with ID: ${data.download_id}`);
                return;
            }

            if (data.status === 'cancelled') {
                cancelled = true;
                return;
            }

            // Process progress updates for our current active download
            if (data.status === 'progress' && data.download_id && data.download_id.startsWith(batchDownloadId)) {
                // Update current LoRA progress
                currentLoraProgress = data.progress;

                // Get current LoRA name
                const currentLora = this.importManager.downloadableLoRAs[completedDownloads + failedDownloads];
                const loraName = currentLora ? currentLora.name : '';

                // Update progress display
                const metrics = {
                    bytesDownloaded: data.bytes_downloaded,
                    totalBytes: data.total_bytes,
                    bytesPerSecond: data.bytes_per_second
                };

                updateProgress(currentLoraProgress, completedDownloads, loraName, metrics);

                // Add more detailed status messages based on progress
                if (currentLoraProgress < 3) {
                    this.importManager.loadingManager.setStatus(
                        `Preparing download for LoRA ${completedDownloads + failedDownloads + 1}/${this.importManager.downloadableLoRAs.length}`
                    );
                } else if (currentLoraProgress === 3) {
                    this.importManager.loadingManager.setStatus(
                        `Downloaded preview for LoRA ${completedDownloads + failedDownloads + 1}/${this.importManager.downloadableLoRAs.length}`
                    );
                } else if (currentLoraProgress > 3 && currentLoraProgress < 100) {
                    this.importManager.loadingManager.setStatus(
                        `Downloading LoRA ${completedDownloads + failedDownloads + 1}/${this.importManager.downloadableLoRAs.length}`
                    );
                } else {
                    this.importManager.loadingManager.setStatus(
                        `Finalizing LoRA ${completedDownloads + failedDownloads + 1}/${this.importManager.downloadableLoRAs.length}`
                    );
                }
            }
        };

        const useDefaultPaths = getStorageItem('use_default_path_loras', false);

        for (let i = 0; i < this.importManager.downloadableLoRAs.length; i++) {
            if (cancelled) break;

            const lora = this.importManager.downloadableLoRAs[i];

            // Reset current LoRA progress for new download
            currentLoraProgress = 0;

            // Initial status update for new LoRA
            this.importManager.loadingManager.setStatus(translate('recipes.controls.import.startingDownload', { current: i + 1, total: this.importManager.downloadableLoRAs.length }, `Starting download for LoRA ${i + 1}/${this.importManager.downloadableLoRAs.length}`));
            updateProgress(0, completedDownloads, lora.name);

            try {
                // Download the LoRA with download ID
                const response = await getModelApiClient(MODEL_TYPES.LORA).downloadModel(
                    lora.modelId,
                    lora.id,
                    loraRoot,
                    targetPath.replace(loraRoot + '/', ''),
                    useDefaultPaths,
                    batchDownloadId
                );

                if (cancelled) break;

                if (!response.success) {
                    console.error(`Failed to download LoRA ${lora.name}: ${response.error}`);
                    failedDownloads++;
                } else {
                    completedDownloads++;
                    updateProgress(100, completedDownloads, '');

                    if (completedDownloads + failedDownloads < this.importManager.downloadableLoRAs.length) {
                        this.importManager.loadingManager.setStatus(
                            `Completed ${completedDownloads}/${this.importManager.downloadableLoRAs.length} LoRAs. Starting next download...`
                        );
                    }
                }
            } catch (downloadError) {
                if (!cancelled) {
                    console.error(`Error downloading LoRA ${lora.name}:`, downloadError);
                    failedDownloads++;
                }
            }
        }

        // Close WebSocket
        ws.close();

        // Show appropriate completion message based on results
        if (cancelled) {
            showToast('toast.downloads.downloadStopped', {}, 'info',
                `Download cancelled. ${completedDownloads} item(s) completed.`);
        } else if (failedDownloads === 0) {
            showToast('toast.loras.allDownloadSuccessful', { count: completedDownloads }, 'success');
        } else {
            if (accessFailures > 0) {
                showToast('toast.loras.downloadPartialWithAccess', {
                    completed: completedDownloads,
                    total: this.importManager.downloadableLoRAs.length,
                    accessFailures: accessFailures
                }, 'error');
            } else {
                showToast('toast.loras.downloadPartialSuccess', {
                    completed: completedDownloads,
                    total: this.importManager.downloadableLoRAs.length
                }, 'error');
            }
        }

        return failedDownloads;
    }
}
