<script lang="ts">
  import type { PicletGeneratorProps, PicletWorkflowState, CaptionType, CaptionLength, PicletStats } from '$lib/types';
  import type { PicletInstance, DiscoveryStatus } from '$lib/db/schema';
  import UploadStep from './UploadStep.svelte';
  import WorkflowProgress from './WorkflowProgress.svelte';
  import PicletResult from './PicletResult.svelte';
  import { removeBackground } from '$lib/utils/professionalImageProcessing';
  import { extractPicletMetadata } from '$lib/services/picletMetadata';
  import { savePicletInstance, generatedDataToPicletInstance } from '$lib/db/piclets';
  import { PicletType, TYPE_DATA } from '$lib/types/picletTypes';
  import { EnhancedCaptionService } from '$lib/services/enhancedCaption';
  import { CanonicalService } from '$lib/services/canonicalService';
  import { incrementDiscoveryCounter, addRarityScore, calculateRarityPoints } from '$lib/db/gameState';
  // import { withQwenTimeout } from '$lib/utils/qwenTimeout'; // Unused since qwen is disabled
  
  interface Props extends PicletGeneratorProps {}

  let {
    joyCaptionClient,
    fluxClient,
    gptOssClient
  }: Props = $props();
  
  // GPT-OSS-120B text generation
  const generateText = async (prompt: string): Promise<string> => {
    if (!gptOssClient) {
      throw new Error('GPT-OSS-120B client is not available');
    }

    console.log('Generating text with GPT-OSS-120B...');

    // ChatInterface expects: message, history, system_prompt, temperature
    const result = await gptOssClient.predict("/chat", [
      prompt,    // message
      [],        // history
      "You are a helpful assistant that creates Pokemon-style monster concepts based on real-world objects.", // system_prompt
      0.7        // temperature
    ]);

    // Extract Response section only (GPT-OSS formats with Analysis and Response)
    let responseText = result.data[0] || '';

    const responseMatch = responseText.match(/\*\*💬 Response:\*\*\s*\n\n([\s\S]*)/);
    if (responseMatch) {
      return responseMatch[1].trim();
    }

    // Fallback: extract after "assistantfinal"
    const finalMatch = responseText.match(/assistantfinal\s*([\s\S]*)/);
    if (finalMatch) {
      return finalMatch[1].trim();
    }

    return responseText;
  };
  
  let workflowState: PicletWorkflowState = $state({
    currentStep: 'upload',
    userImage: null,
    imageCaption: null,
    picletConcept: null,
    picletStats: null,
    imagePrompt: null,
    picletImage: null,
    error: null,
    isProcessing: false,
    // Discovery-specific state
    objectName: null,
    objectAttributes: [],
    visualDetails: null,
    discoveryStatus: null,
    canonicalPiclet: null
  });
  
  // Queue state for multi-image processing
  let imageQueue: File[] = $state([]);
  let currentImageIndex: number = $state(0);
  
  const IMAGE_GENERATION_PROMPT = (concept: string) => `Extract ONLY the visual appearance from this monster concept and describe it in one concise sentence:
"${concept}"

Focus on: colors, body shape, eyes, limbs, mouth, and key visual features. Omit backstory, abilities, and non-visual details.`;
  

  async function importPiclet(picletData: PicletInstance) {
    workflowState.isProcessing = true;
    workflowState.currentStep = 'complete';
    
    try {
      // Save the imported piclet
      const savedId = await savePicletInstance(picletData);
      
      // Create a success workflowState similar to generation
      workflowState.picletImage = {
        imageUrl: picletData.imageUrl,
        imageData: picletData.imageData,
        seed: 0,
        prompt: 'Imported piclet'
      };
      
      // Show import success
      workflowState.isProcessing = false;
      alert(`Successfully imported ${picletData.nickname || picletData.typeId}!`);
      
      // Reset to allow another import/generation
      setTimeout(() => reset(), 2000);
    } catch (error) {
      workflowState.error = `Failed to import piclet: ${error}`;
      workflowState.isProcessing = false;
    }
  }

  async function handleImageSelected(file: File) {
    if (!joyCaptionClient || !fluxClient) {
      workflowState.error = "Services not connected. Please wait...";
      return;
    }
    
    // Single image upload - clear queue and process normally
    imageQueue = [];
    currentImageIndex = 0;
    
    workflowState.userImage = file;
    workflowState.error = null;
    
    // Check if this is a piclet card with metadata
    const picletData = await extractPicletMetadata(file);
    if (picletData) {
      // Import existing piclet
      await importPiclet(picletData);
    } else {
      // Generate new piclet
      startWorkflow();
    }
  }
  
  async function handleImagesSelected(files: File[]) {
    if (!joyCaptionClient || !fluxClient) {
      workflowState.error = "Services not connected. Please wait...";
      return;
    }
    
    // Multi-image upload - set up queue and start with first image
    imageQueue = files;
    currentImageIndex = 0;
    
    await processCurrentImage();
  }
  
  async function processCurrentImage() {
    if (currentImageIndex >= imageQueue.length) {
      // Queue completed
      console.log('All images processed!');
      return;
    }
    
    const currentFile = imageQueue[currentImageIndex];
    workflowState.userImage = currentFile;
    workflowState.error = null;
    
    // Check if this is a piclet card with metadata
    const picletData = await extractPicletMetadata(currentFile);
    if (picletData) {
      // Import existing piclet
      await importPiclet(picletData);
      // Auto-advance to next image after import
      await advanceToNextImage();
    } else {
      // Generate new piclet
      startWorkflow();
    }
  }
  
  async function advanceToNextImage() {
    currentImageIndex++;
    
    if (currentImageIndex < imageQueue.length) {
      // Process next image
      setTimeout(() => processCurrentImage(), 1000); // Small delay for better UX
    } else {
      // Queue completed - reset to single image mode
      imageQueue = [];
      currentImageIndex = 0;
      reset();
    }
  }
  
  async function startWorkflow() {
    workflowState.isProcessing = true;

    try {
      // Step 1: Generate detailed object description with joy-caption (skip server lookup for now)
      await captionImage();
      await new Promise(resolve => setTimeout(resolve, 100)); // Small delay for workflowState update

      // Step 2: Generate free-form monster concept with Qwen
      await generateConcept();
      await new Promise(resolve => setTimeout(resolve, 100)); // Small delay for workflowState update

      // Step 3: Extract stats including physical characteristics
      await extractSimpleStats();
      await new Promise(resolve => setTimeout(resolve, 100)); // Small delay for workflowState update

      // Step 4: Generate image prompt with Qwen
      await generateImagePrompt();
      await new Promise(resolve => setTimeout(resolve, 100)); // Small delay for workflowState update

      // Step 5: Generate monster image with anime style
      await generateMonsterImage();

      // Step 6: Auto-save the piclet as caught (since scanning now auto-captures)
      await autoSavePicletAsCaught();

      workflowState.currentStep = 'complete';

      // If processing a queue, auto-advance to next image after a short delay
      if (imageQueue.length > 1) {
        setTimeout(() => advanceToNextImage(), 2000); // 2 second delay to show completion
      }
    } catch (err) {
      console.error('Workflow error:', err);

      // Check for GPU quota error
      if (err && typeof err === 'object' && 'message' in err) {
        const errorMessage = String(err.message);
        if (errorMessage.includes('exceeded your GPU quota') || errorMessage.includes('GPU quota')) {
          workflowState.error = 'GPU quota exceeded! You need to sign in with Hugging Face for free GPU time, or upgrade to Hugging Face Pro for more quota.';
        } else {
          workflowState.error = errorMessage;
        }
      } else if (err instanceof Error) {
        workflowState.error = err.message;
      } else {
        workflowState.error = 'An unknown error occurred';
      }
    } finally {
      workflowState.isProcessing = false;
    }
  }
  
  function handleAPIError(error: any): never {
    console.error('API Error:', error);
    
    // Check if it's a GPU quota error
    if (error && typeof error === 'object' && 'message' in error) {
      const errorMessage = String(error.message);
      if (errorMessage.includes('exceeded your GPU quota') || errorMessage.includes('GPU quota')) {
        throw new Error('GPU quota exceeded! You need to sign in with Hugging Face for free GPU time, or upgrade to Hugging Face Pro for more quota.');
      }
      throw new Error(errorMessage);
    }
    
    // Check if error has a different structure (like the status object from the logs)
    if (error && typeof error === 'object' && 'type' in error && error.type === 'status') {
      const statusError = error as any;
      if (statusError.message && statusError.message.includes('GPU quota')) {
        throw new Error('GPU quota exceeded! You need to sign in with Hugging Face for free GPU time, or upgrade to Hugging Face Pro for more quota.');
      }
      throw new Error(statusError.message || 'API request failed');
    }
    
    throw error;
  }
  
  async function captionImage() {
    workflowState.currentStep = 'captioning';

    if (!joyCaptionClient || !workflowState.userImage) {
      throw new Error('Caption service not available or no image provided');
    }

    try {
      // Get detailed scene description from Joy Caption
      const captionResult = await EnhancedCaptionService.generateEnhancedCaption(
        joyCaptionClient,
        workflowState.userImage
      );

      workflowState.imageCaption = captionResult.caption;
      console.log('Scene description:', captionResult.caption);

      // Skip server lookup for now - always create new piclet
      workflowState.discoveryStatus = 'new';
    } catch (error) {
      handleAPIError(error);
    }
  }
  
  async function generateConcept() {
    workflowState.currentStep = 'conceptualizing';

    // Skip if we have an existing canonical Piclet
    if (workflowState.discoveryStatus === 'existing' && workflowState.canonicalPiclet) {
      workflowState.picletConcept = workflowState.canonicalPiclet.concept;
      console.log('Using existing canonical concept');
      return;
    }

    if (!gptOssClient || !workflowState.imageCaption) {
      throw new Error('Cannot generate concept without scene description');
    }

    const conceptPrompt = `You are analyzing an image to create a Pokemon-style creature. Here's the image description:

"${workflowState.imageCaption}"

Your task:
1. Identify the PRIMARY PHYSICAL OBJECT with SPECIFICITY (e.g., "macbook" not "laptop", "eiffel tower" not "tower", "iphone" not "phone", "starbucks mug" not "mug")
2. Determine if there's a meaningful VARIATION (e.g., "silver", "pro", "night", "gaming", "vintage")
3. Assess rarity based on uniqueness
4. Create a complete Pokemon-style monster concept

Format your response EXACTLY as follows:
\`\`\`md
# Canonical Object
{Specific object name: "macbook", "eiffel tower", "iphone", "tesla", "le creuset mug", "nintendo switch"}
{NOT generic terms like: "laptop", "tower", "phone", "car", "mug", "console"}
{Include brand/model/landmark name when identifiable}

# Variation
{OPTIONAL: one distinctive attribute like "silver", "pro", "night", "gaming", OR use "canonical" if this is the standard/default version with no special variation}

# Object Rarity
{common, uncommon, rare, epic, or legendary based on object uniqueness}

# Monster Name
{Creative 8-11 letter name based on the SPECIFIC object, e.g., "Macbyte" for MacBook, "Towerfell" for Eiffel Tower}

# Primary Type
{beast, bug, aquatic, flora, mineral, space, machina, structure, culture, or cuisine}

# Physical Stats
Height: {e.g., "1.2m" or "3'5\""}
Weight: {e.g., "15kg" or "33 lbs"}

# Personality
{1-2 sentences describing personality traits}

# Monster Description
{2-3 paragraphs describing how the SPECIFIC object's features translate into monster features. Reference the actual object by name. This is the creature's bio.}

# Monster Image Prompt
{Concise visual description for anime-style image generation focusing on colors, shapes, and key features inspired by the specific object}
\`\`\`

CRITICAL RULES:
- Canonical Object MUST be SPECIFIC: "macbook" not "laptop", "big ben" not "clock tower", "coca cola" not "soda"
- If you can identify a brand, model, or proper name from the description, USE IT
- Variation should be meaningful and distinctive (material, style, color, context, or model variant)
- Monster Description must describe the CREATURE with references to the specific object's features
- Primary Type must match the object category (machina for electronics, structure for buildings, etc.)`;

    try {
      const responseText = await generateText(conceptPrompt);

      // Validate response has expected structure
      if (!responseText.includes('# Canonical Object') ||
          !responseText.includes('# Monster Name')) {
        console.error('GPT-OSS returned invalid response:', responseText);
        throw new Error('Failed to generate valid monster concept');
      }

      workflowState.picletConcept = responseText;

      // Extract and store canonical name and variation immediately for use in other steps
      // Handle both plain and bold markdown headers
      const canonicalMatch = responseText.match(/\*{0,2}#\s*Canonical Object\s*\*{0,2}\s*\n([\s\S]*?)(?=^\*{0,2}#)/m);
      const variationMatch = responseText.match(/\*{0,2}#\s*Variation\s*\*{0,2}\s*\n([\s\S]*?)(?=^\*{0,2}#)/m);

      // Clean up extracted values (remove curly braces and quotes that GPT-OSS sometimes adds)
      let objectName = canonicalMatch ? canonicalMatch[1].trim().toLowerCase() : 'unknown';
      objectName = objectName.replace(/^[{"]|["}]$/g, '').replace(/^.*:\s*["']|["']$/g, '').trim();

      let variationText = variationMatch ? variationMatch[1].trim() : '';
      variationText = variationText.replace(/^[{"]|["}]$/g, '').replace(/^.*:\s*["']|["']$/g, '').trim();

      workflowState.objectName = objectName;
      workflowState.objectAttributes = variationText && variationText !== 'NONE' && variationText !== 'canonical' ? [variationText.toLowerCase()] : [];

      console.log('Parsed specific object:', workflowState.objectName);
      console.log('Parsed variation:', workflowState.objectAttributes);
      
      if (!responseText || responseText.trim() === '') {
        throw new Error('Failed to generate monster concept');
      }
      
      // Parse markdown code block response
      let cleanedResponse = responseText.trim();
      
      // Check if response is wrapped in markdown code blocks
      if (cleanedResponse.includes('```')) {
        // Handle different code block formats: ```md, ```, ```markdown
        const codeBlockRegex = /```(?:md|markdown)?\s*\n([\s\S]*?)```/;
        const match = cleanedResponse.match(codeBlockRegex);
        
        if (match && match[1]) {
          cleanedResponse = match[1].trim();
          console.log('Extracted content from markdown code block');
        } else {
          // Fallback: try to extract content between any ``` blocks
          const simpleMatch = cleanedResponse.match(/```([\s\S]*?)```/);
          if (simpleMatch && simpleMatch[1]) {
            cleanedResponse = simpleMatch[1].trim();
            console.log('Extracted content from generic code block');
          }
        }
      }
      
      // Ensure the response contains expected markdown headers
      if (!cleanedResponse.includes('# Object Rarity') || !cleanedResponse.includes('# Monster Name') || !cleanedResponse.includes('# Monster Image Prompt')) {
        console.warn('Response does not contain expected markdown structure (missing Object Rarity, Monster Name, or Monster Image Prompt)');
      }
      
      workflowState.picletConcept = cleanedResponse;
      console.log('Monster concept generated:', cleanedResponse);
    } catch (error) {
      handleAPIError(error);
    }
  }
  
  async function generateImagePrompt() {
    workflowState.currentStep = 'promptCrafting';
    
    if (!gptOssClient || !workflowState.picletConcept || !workflowState.imageCaption) {
      throw new Error('Text generation service not available or no concept/caption available for prompt generation');
    }
    
    // Extract the Monster Image Prompt from the structured concept (handle both plain and bold markdown headers)
    const imagePromptMatch = workflowState.picletConcept.match(/\*{0,2}#\s*Monster Image Prompt\s*\*{0,2}\s*\n([\s\S]*?)(?=^\*{0,2}#|$)/m);
    
    if (imagePromptMatch && imagePromptMatch[1]) {
      workflowState.imagePrompt = imagePromptMatch[1].trim();
      console.log('Extracted image prompt for generation:', workflowState.imagePrompt);
      return; // Skip fallback call since we have the prompt
    }
    
    // Fallback: if format parsing fails, use Qwen to extract visual description
    const imagePromptPrompt = `Based on this monster concept, extract ONLY the visual description for image generation:

MONSTER CONCEPT:
"""
${workflowState.picletConcept}
"""

Create a concise visual description (1-3 sentences, max 100 words). Focus only on colors, shapes, materials, eyes, limbs, mouth, and distinctive features. Omit all non-visual information like abilities and backstory.`;
    
    try {
      const responseText = await generateText(imagePromptPrompt);
      
      if (!responseText || responseText.trim() === '') {
        throw new Error('Failed to generate image prompt');
      }
      
      workflowState.imagePrompt = responseText.trim();
      console.log('Image prompt generated:', workflowState.imagePrompt);
    } catch (error) {
      handleAPIError(error);
    }
  }
  
  async function generateMonsterImage() {
    workflowState.currentStep = 'generating';
    
    if (!fluxClient || !workflowState.imagePrompt || !workflowState.picletStats) {
      throw new Error('Image generation service not available or no prompt/stats');
    }
    
    // The image prompt should already be generated by generateImagePrompt() in the workflow
    
    // Get tier for image quality enhancement
    const tier = workflowState.picletStats.tier || 'medium';
    const tierDescriptions = {
      low: 'simple and iconic design',
      medium: 'detailed and well-crafted design', 
      high: 'highly detailed and impressive design with special effects',
      legendary: 'highly detailed and majestic design with dramatic lighting and aura effects'
    };
    
    try {
      const output = await fluxClient.predict("/infer", [
        `${workflowState.imagePrompt}\nNow generate an Pokémon Anime image of the monster in an idle pose with a plain dark-grey background. This is a ${tier} tier monster with a ${tierDescriptions[tier as keyof typeof tierDescriptions]}. The monster should not be attacking or in motion. The full monster must be visible within the frame.`,
        0,      // seed
        true,   // randomizeSeed
        1024,   // width
        1024,   // height
        4       // steps
      ]);
      
      const [image, usedSeed] = output.data;
      let url: string | undefined;
      
      if (typeof image === "string") url = image;
      else if (image && image.url) url = image.url;
      else if (image && image.path) url = image.path;
      
      if (url) {
        // Process the image to remove background using professional AI method
        console.log('Processing image for background removal...');
        try {
          const transparentBase64 = await removeBackground(url);
          workflowState.picletImage = {
            imageUrl: url,
            imageData: transparentBase64,
            seed: usedSeed,
            prompt: workflowState.imagePrompt
          };
          console.log('Background removal completed successfully');
        } catch (processError) {
          console.error('Failed to process image for background removal:', processError);
          // Fallback to original image
          workflowState.picletImage = {
            imageUrl: url,
            seed: usedSeed,
            prompt: workflowState.imagePrompt
          };
        }
      } else {
        throw new Error('Failed to generate monster image');
      }
    } catch (error) {
      handleAPIError(error);
    }
  }
  
  async function extractSimpleStats() {
    workflowState.currentStep = 'statsGenerating';

    if (!workflowState.picletConcept) {
      throw new Error('No concept available for stats extraction');
    }

    try {
      // Extract monster name (handle both plain and bold markdown headers)
      const monsterNameMatch = workflowState.picletConcept.match(/\*{0,2}#\s*Monster Name\s*\*{0,2}\s*\n([\s\S]*?)(?=^\*{0,2}#|$)/m);
      let monsterName = monsterNameMatch ? monsterNameMatch[1].trim() : 'Unknown Monster';

      // Clean and truncate name
      monsterName = monsterName.replace(/^[{"]|["}]$/g, '').trim(); // Remove curly braces and quotes
      if (monsterName.includes(',')) {
        monsterName = monsterName.split(',')[0].trim();
      }
      if (monsterName.length > 12) {
        monsterName = monsterName.substring(0, 12);
      }
      monsterName = monsterName.replace(/\*/g, ''); // Remove markdown asterisks

      // Extract rarity and convert to tier (handle both plain and bold markdown headers)
      const rarityMatch = workflowState.picletConcept.match(/\*{0,2}#\s*Object Rarity\s*\*{0,2}\s*\n([\s\S]*?)(?=^\*{0,2}#)/m);
      const objectRarity = rarityMatch ? rarityMatch[1].trim().toLowerCase() : 'common';

      let tier: 'low' | 'medium' | 'high' | 'legendary' = 'medium';
      if (objectRarity.includes('common')) tier = 'low';
      else if (objectRarity.includes('uncommon')) tier = 'medium';
      else if (objectRarity.includes('rare')) tier = 'high';
      else if (objectRarity.includes('legendary') || objectRarity.includes('mythical')) tier = 'legendary';

      // Extract primary type (handle both plain and bold markdown headers)
      const primaryTypeMatch = workflowState.picletConcept.match(/\*{0,2}#\s*Primary Type\s*\*{0,2}\s*\n([\s\S]*?)(?=^\*{0,2}#|$)/m);
      let primaryType: any = primaryTypeMatch ? primaryTypeMatch[1].trim().toLowerCase() : 'beast';
      primaryType = primaryType.replace(/^[{"]|["}]$/g, '').trim(); // Remove curly braces and quotes

      // Extract description (handle both plain and bold markdown headers)
      const descriptionMatch = workflowState.picletConcept.match(/\*{0,2}#\s*Monster Description\s*\*{0,2}\s*\n([\s\S]*?)(?=^\*{0,2}#|$)/m);
      if (!descriptionMatch) {
        console.error('Monster description not found in concept:', workflowState.picletConcept);
        throw new Error('Failed to extract monster description from AI response');
      }
      let description = descriptionMatch[1].trim();

      // Extract physical stats (handle both plain and bold markdown headers)
      const physicalStatsMatch = workflowState.picletConcept.match(/\*{0,2}#\s*Physical Stats\s*\*{0,2}\s*\n([\s\S]*?)(?=^\*{0,2}#|$)/m);
      let height: string | undefined;
      let weight: string | undefined;

      if (physicalStatsMatch) {
        const physicalStatsText = physicalStatsMatch[1];
        const heightMatch = physicalStatsText.match(/Height:\s*(.+)/i);
        const weightMatch = physicalStatsText.match(/Weight:\s*(.+)/i);

        height = heightMatch ? heightMatch[1].trim().replace(/^[{"]|["}]$/g, '').trim() : undefined;
        weight = weightMatch ? weightMatch[1].trim().replace(/^[{"]|["}]$/g, '').trim() : undefined;
      }

      // Extract personality (handle both plain and bold markdown headers)
      const personalityMatch = workflowState.picletConcept.match(/\*{0,2}#\s*Personality\s*\*{0,2}\s*\n([\s\S]*?)(?=^\*{0,2}#|$)/m);
      let personality = personalityMatch ? personalityMatch[1].trim().replace(/^[{"]|["}]$/g, '').trim() : undefined;

      // Create stats with physical characteristics
      const stats: PicletStats = {
        name: monsterName,
        description: description,
        tier: tier,
        primaryType: primaryType,
        height,
        weight,
        personality
      };

      workflowState.picletStats = stats;
      console.log('Stats extracted:', stats);

    } catch (error) {
      console.error('Failed to extract stats:', error);
      handleAPIError(error);
    }
  }
  
  async function autoSavePicletAsCaught() {
    if (!workflowState.picletImage || !workflowState.imageCaption || !workflowState.picletConcept || !workflowState.imagePrompt || !workflowState.picletStats) {
      console.error('Cannot auto-save: missing required data');
      return;
    }
    
    try {
      // Create a clean copy of stats to ensure it's serializable
      const cleanStats = JSON.parse(JSON.stringify(workflowState.picletStats));
      
      const picletData = {
        name: workflowState.picletStats.name,
        imageUrl: workflowState.picletImage.imageUrl,
        imageData: workflowState.picletImage.imageData,
        imageCaption: workflowState.imageCaption,
        concept: workflowState.picletConcept,
        imagePrompt: workflowState.imagePrompt,
        stats: cleanStats,
        createdAt: new Date()
      };
      
      // Check for any non-serializable data
      console.log('Checking piclet data for serializability:');
      console.log('- name type:', typeof picletData.name);
      console.log('- imageUrl type:', typeof picletData.imageUrl);
      console.log('- imageData type:', typeof picletData.imageData, picletData.imageData ? `length: ${picletData.imageData.length}` : 'null/undefined');
      console.log('- imageCaption type:', typeof picletData.imageCaption);
      console.log('- concept type:', typeof picletData.concept);
      console.log('- imagePrompt type:', typeof picletData.imagePrompt);
      console.log('- stats:', cleanStats);
      
      // Convert to PicletInstance format and save as caught
      // Convert reactive Svelte state to plain values (removes Proxy wrapper for IndexedDB compatibility)
      const plainAttributes = workflowState.objectAttributes ? [...workflowState.objectAttributes] : [];

      const picletInstance = await generatedDataToPicletInstance(
        picletData,
        workflowState.objectName || undefined,
        plainAttributes,
        workflowState.visualDetails || undefined
      );

      const picletId = await savePicletInstance(picletInstance);
      console.log('Piclet auto-saved as caught with ID:', picletId);

      // Update game state statistics
      await incrementDiscoveryCounter('totalDiscoveries');

      // Update canonical vs variation counters
      if (picletInstance.isCanonical) {
        await incrementDiscoveryCounter('uniqueDiscoveries');
      } else {
        await incrementDiscoveryCounter('variationsFound');
      }

      // Calculate and add rarity score
      const rarityPoints = calculateRarityPoints(picletInstance.scanCount);
      await addRarityScore(rarityPoints);

      console.log('Game state updated: +1 discovery, +' + rarityPoints + ' rarity points');
    } catch (err) {
      console.error('Failed to auto-save piclet:', err);
      console.error('Piclet data that failed to save:', {
        name: workflowState.picletStats?.name,
        hasImageUrl: !!workflowState.picletImage?.imageUrl,
        hasImageData: !!workflowState.picletImage?.imageData,
        hasStats: !!workflowState.picletStats
      });

      // Don't throw - we don't want to interrupt the workflow
    }
  }
  
  function reset() {
    workflowState = {
      currentStep: 'upload',
      userImage: null,
      imageCaption: null,
      picletConcept: null,
      picletStats: null,
      imagePrompt: null,
      picletImage: null,
      error: null,
      isProcessing: false,
      objectName: null,
      objectAttributes: [],
      visualDetails: null,
      discoveryStatus: null,
      canonicalPiclet: null
    };
  }
</script>

<div class="piclet-generator">
  
  
  {#if workflowState.currentStep !== 'upload'}
    <WorkflowProgress currentStep={workflowState.currentStep} error={workflowState.error} />
  {/if}
  
  {#if workflowState.currentStep === 'upload'}
    <UploadStep 
      onImageSelected={handleImageSelected}
      onImagesSelected={handleImagesSelected}
      isProcessing={workflowState.isProcessing}
      imageQueue={imageQueue}
      currentImageIndex={currentImageIndex}
    />
  {:else if workflowState.currentStep === 'complete'}
    <PicletResult workflowState={workflowState} onReset={reset} />
  {:else}
    <div class="processing-container">
      <div class="spinner"></div>
      <p class="processing-text">
        {#if workflowState.currentStep === 'captioning'}
          Analyzing your image...
        {:else if workflowState.currentStep === 'conceptualizing'}
          Creating Piclet concept...
        {:else if workflowState.currentStep === 'statsGenerating'}
          Generating piclet characteristics...
        {:else if workflowState.currentStep === 'promptCrafting'}
          Creating image prompt...
        {:else if workflowState.currentStep === 'generating'}
          Generating your Piclet...
        {/if}
      </p>
    </div>
  {/if}
</div>

<style>
  .piclet-generator {
    width: 100%;
    max-width: 1200px;
    margin: 0 auto;
    padding: 2rem;
  }
  
  /* Client selector styles (hidden since only HunyuanTurbos is active) */
  /*
  .client-selector {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    margin-bottom: 1rem;
    padding: 0.75rem;
    background: #f8f9fa;
    border-radius: 8px;
    border: 1px solid #dee2e6;
  }
  
  .client-selector label {
    font-weight: 500;
    color: #495057;
  }
  
  .client-selector select {
    padding: 0.25rem 0.5rem;
    border: 1px solid #ced4da;
    border-radius: 4px;
    background: white;
    color: #495057;
    font-size: 0.9rem;
  }
  */
  
  
  .processing-container {
    display: flex;
    flex-direction: column;
    align-items: center;
    padding: 3rem 1rem;
  }
  
  .spinner {
    width: 60px;
    height: 60px;
    border: 3px solid #f3f3f3;
    border-top: 3px solid #007bff;
    border-radius: 50%;
    animation: spin 1s linear infinite;
    margin-bottom: 2rem;
  }
  
  @keyframes spin {
    0% { transform: rotate(0deg); }
    100% { transform: rotate(360deg); }
  }
  
  .processing-text {
    font-size: 1.2rem;
    color: #333;
    margin-bottom: 2rem;
  }
  
</style>