export interface JasonPrompt {
  prompt: string
  style: string
  characters?: string[]
  mood?: string
  consistency?: {
    characterFeatures?: Record<string, any>
    itemFeatures?: Record<string, any>
    colorPalette?: string[]
    style?: string
  }
  metadata?: {
    version?: string
    timestamp?: string
    engine?: string
    seriesId?: string
    imageIndex?: number
  }
}

export interface CharacterConsistency {
  name: string
  description: string
  features: {
    hair: string
    eyes: string
    clothing: string
    accessories: string[]
    expression: string
    pose?: string
    colorPalette?: string[]
  }
  consistency: {
    mustMaintain: string[]
    canVary: string[]
    priority: 'high' | 'medium' | 'low'
  }
}

export interface ItemConsistency {
  name: string
  description: string
  features: {
    color: string
    material: string
    size: string
    position?: string
    lighting?: string
  }
  consistency: {
    mustMaintain: string[]
    canVary: string[]
    priority: 'high' | 'medium' | 'low'
  }
}

export interface SeriesConsistency {
  characters: CharacterConsistency[]
  items: ItemConsistency[]
  colorPalette: string[]
  style: string
  mood: string
  narrativeProgression: {
    start: string
    middle: string
    end: string
  }
}

export class JasonProcessor {
  private jasonPatterns = {
    basic: /^{[\s\S]*}$/,
    prompt: /"prompt"\s*:\s*"([^"]+)"/,
    style: /"style"\s*:\s*"([^"]+)"/,
    characters: /"characters"\s*:\s*(\[.*?\])/,
    mood: /"mood"\s*:\s*"([^"]+)"/,
    consistency: /"consistency"\s*:\s*{[\s\S]*?}/,
  }

  parseJasonPrompt(jasonString: string): JasonPrompt | null {
    try {
      // Clean the input
      const cleaned = jasonString.trim()
      
      if (!cleaned.startsWith('{') || !cleaned.endsWith('}')) {
        throw new Error('Invalid Jason format: must be a JSON object')
      }

      // Parse JSON
      const parsed = JSON.parse(cleaned)
      
      // Validate required fields
      if (!parsed.prompt || typeof parsed.prompt !== 'string') {
        throw new Error('Invalid Jason format: prompt is required')
      }

      return {
        prompt: parsed.prompt,
        style: parsed.style || 'realistic',
        characters: parsed.characters || [],
        mood: parsed.mood || 'neutral',
        consistency: parsed.consistency || {},
        metadata: parsed.metadata || {},
      }

    } catch (error) {
      console.error('Failed to parse Jason prompt:', error)
      return null
    }
  }

  generateJasonFromPrompt(
    prompt: string,
    options: {
      style?: string
      characters?: string[]
      mood?: string
      consistency?: Partial<JasonPrompt['consistency']>
      metadata?: Partial<JasonPrompt['metadata']>
    } = {}
  ): string {
    const {
      style = 'realistic',
      characters = [],
      mood = 'neutral',
      consistency = {},
      metadata = {},
    } = options

    const jasonPrompt: JasonPrompt = {
      prompt,
      style,
      characters,
      mood,
      consistency: {
        characterFeatures: {
          style,
          mood,
          ...consistency.characterFeatures,
        },
        itemFeatures: {
          style,
          quality: 'high',
          ...consistency.itemFeatures,
        },
        ...consistency,
      },
      metadata: {
        version: '1.0',
        timestamp: new Date().toISOString(),
        engine: 'nanojason',
        ...metadata,
      },
    }

    return JSON.stringify(jasonPrompt, null, 2)
  }

  extractConsistencyProfiles(
    prompts: JasonPrompt[]
  ): SeriesConsistency {
    const characters: CharacterConsistency[] = []
    const items: ItemConsistency[] = []
    const colorPalette = new Set<string>()
    const styleSet = new Set<string>()
    const moodSet = new Set<string>()

    prompts.forEach((prompt, index) => {
      // Extract style
      if (prompt.style) {
        styleSet.add(prompt.style)
      }

      // Extract mood
      if (prompt.mood) {
        moodSet.add(prompt.mood)
      }

      // Extract color palette from consistency
      if (prompt.consistency?.colorPalette) {
        prompt.consistency.colorPalette.forEach(color => colorPalette.add(color))
      }

      // Extract characters
      if (prompt.characters) {
        prompt.characters.forEach(characterName => {
          const existingCharacter = characters.find(c => c.name === characterName)
          
          if (!existingCharacter) {
            characters.push({
              name: characterName,
              description: `Character from prompt ${index + 1}`,
              features: this.extractCharacterFeatures(prompt),
              consistency: {
                mustMaintain: ['name', 'style'],
                canVary: ['pose', 'expression', 'position'],
                priority: 'high',
              },
            })
          } else {
            // Merge features for existing character
            existingCharacter.features = this.mergeCharacterFeatures(
              existingCharacter.features,
              this.extractCharacterFeatures(prompt)
            )
          }
        })
      }

      // Extract items from prompt
      const itemsInPrompt = this.extractItemsFromPrompt(prompt.prompt)
      itemsInPrompt.forEach(itemName => {
        const existingItem = items.find(i => i.name === itemName)
        
        if (!existingItem) {
          items.push({
            name: itemName,
            description: `Item from prompt ${index + 1}`,
            features: this.extractItemFeatures(prompt, itemName),
            consistency: {
              mustMaintain: ['name', 'style'],
              canVary: ['position', 'lighting', 'size'],
              priority: 'medium',
            },
          })
        } else {
          // Merge features for existing item
          existingItem.features = this.mergeItemFeatures(
            existingItem.features,
            this.extractItemFeatures(prompt, itemName)
          )
        }
      })
    })

    return {
      characters,
      items,
      colorPalette: Array.from(colorPalette),
      style: Array.from(styleSet)[0] || 'realistic',
      mood: Array.from(moodSet)[0] || 'neutral',
      narrativeProgression: this.extractNarrativeProgression(prompts),
    }
  }

  private extractCharacterFeatures(prompt: JasonPrompt): CharacterConsistency['features'] {
    // Simple feature extraction - in production, this would use NLP
    const features: CharacterConsistency['features'] = {
      hair: 'unknown',
      eyes: 'unknown',
      clothing: 'unknown',
      accessories: [],
      expression: 'neutral',
    }

    // Extract from prompt text
    const promptText = prompt.prompt.toLowerCase()
    
    if (promptText.includes('long hair')) features.hair = 'long'
    if (promptText.includes('short hair')) features.hair = 'short'
    if (promptText.includes('blue eyes')) features.eyes = 'blue'
    if (promptText.includes('brown eyes')) features.eyes = 'brown'
    if (promptText.includes('green eyes')) features.eyes = 'green'
    
    if (promptText.includes('wearing')) {
      const clothingMatch = promptText.match(/wearing\s+([a-z\s]+)/)
      if (clothingMatch) {
        features.clothing = clothingMatch[1]
      }
    }

    if (promptText.includes('smiling')) features.expression = 'smiling'
    if (promptText.includes('sad')) features.expression = 'sad'
    if (promptText.includes('angry')) features.expression = 'angry'

    return features
  }

  private extractItemFeatures(prompt: JasonPrompt, itemName: string): ItemConsistency['features'] {
    const features: ItemConsistency['features'] = {
      color: 'unknown',
      material: 'unknown',
      size: 'unknown',
    }

    const promptText = prompt.prompt.toLowerCase()
    
    // Extract color
    const colorPatterns = ['red', 'blue', 'green', 'yellow', 'black', 'white', 'gold', 'silver']
    const foundColor = colorPatterns.find(color => promptText.includes(color))
    if (foundColor) {
      features.color = foundColor
    }

    // Extract material
    const materialPatterns = ['wooden', 'metal', 'crystal', 'glass', 'stone', 'fabric']
    const foundMaterial = materialPatterns.find(material => promptText.includes(material))
    if (foundMaterial) {
      features.material = foundMaterial
    }

    // Extract size
    if (promptText.includes('large')) features.size = 'large'
    if (promptText.includes('small')) features.size = 'small'
    if (promptText.includes('tiny')) features.size = 'tiny'

    return features
  }

  private mergeCharacterFeatures(
    existing: CharacterConsistency['features'],
    newFeatures: CharacterConsistency['features']
  ): CharacterConsistency['features'] {
    return {
      hair: newFeatures.hair !== 'unknown' ? newFeatures.hair : existing.hair,
      eyes: newFeatures.eyes !== 'unknown' ? newFeatures.eyes : existing.eyes,
      clothing: newFeatures.clothing !== 'unknown' ? newFeatures.clothing : existing.clothing,
      accessories: [...existing.accessories, ...newFeatures.accessories],
      expression: newFeatures.expression !== 'neutral' ? newFeatures.expression : existing.expression,
      colorPalette: existing.colorPalette || newFeatures.colorPalette,
    }
  }

  private mergeItemFeatures(
    existing: ItemConsistency['features'],
    newFeatures: ItemConsistency['features']
  ): ItemConsistency['features'] {
    return {
      color: newFeatures.color !== 'unknown' ? newFeatures.color : existing.color,
      material: newFeatures.material !== 'unknown' ? newFeatures.material : existing.material,
      size: newFeatures.size !== 'unknown' ? newFeatures.size : existing.size,
      position: newFeatures.position || existing.position,
      lighting: newFeatures.lighting || existing.lighting,
    }
  }

  private extractItemsFromPrompt(promptText: string): string[] {
    const items: string[] = []
    
    // Common item patterns
    const itemPatterns = [
      /\b(sword|knife|blade)\b/gi,
      /\b(staff|wand|rod)\b/gi,
      /\b(book|scroll|tome)\b/gi,
      /\b(crown|tiara|diadem)\b/gi,
      /\b(crystal|gem|stone)\b/gi,
      /\b(key|lock|chest)\b/gi,
      /\b(map|compass|treasure)\b/gi,
      /\b(armor|shield|helmet)\b/gi,
      /\b(flower|plant|tree)\b/gi,
      /\b(building|house|castle)\b/gi,
    ]

    itemPatterns.forEach(pattern => {
      const matches = promptText.match(pattern)
      if (matches) {
        matches.forEach(match => {
          const cleanMatch = match.toLowerCase()
          if (!items.includes(cleanMatch)) {
            items.push(cleanMatch)
          }
        })
      }
    })

    return items
  }

  private extractNarrativeProgression(prompts: JasonPrompt[]): SeriesConsistency['narrativeProgression'] {
    const total = prompts.length
    
    return {
      start: prompts[0]?.prompt || 'Beginning of story',
      middle: prompts[Math.floor(total / 2)]?.prompt || 'Middle of story',
      end: prompts[total - 1]?.prompt || 'End of story',
    }
  }

  generateConsistencyEnhancedPrompt(
    originalPrompt: string,
    consistencyProfile: SeriesConsistency,
    imageIndex: number,
    totalImages: number
  ): JasonPrompt {
    // Apply consistency rules to enhance the prompt
    let enhancedPrompt = originalPrompt

    // Add character consistency
    if (consistencyProfile.characters.length > 0) {
      const characterDescriptions = consistencyProfile.characters.map(char => 
        `${char.name} with ${char.features.hair} hair and ${char.features.eyes} eyes`
      ).join(', ')
      
      enhancedPrompt += ` featuring ${characterDescriptions}`
    }

    // Add item consistency
    if (consistencyProfile.items.length > 0) {
      const itemDescriptions = consistencyProfile.items.map(item => 
        `${item.name} made of ${item.features.material}`
      ).join(', ')
      
      enhancedPrompt += ` with ${itemDescriptions}`
    }

    // Add style and mood consistency
    enhancedPrompt += ` in ${consistencyProfile.style} style with ${consistencyProfile.mood} atmosphere`

    // Add color palette if available
    if (consistencyProfile.colorPalette.length > 0) {
      enhancedPrompt += `, color palette: ${consistencyProfile.colorPalette.join(', ')}`
    }

    return {
      prompt: enhancedPrompt,
      style: consistencyProfile.style,
      characters: consistencyProfile.characters.map(c => c.name),
      mood: consistencyProfile.mood,
      consistency: {
        characterFeatures: {
          style: consistencyProfile.style,
          mood: consistencyProfile.mood,
        },
        itemFeatures: {
          style: consistencyProfile.style,
        },
        colorPalette: consistencyProfile.colorPalette,
      },
      metadata: {
        version: '1.0',
        timestamp: new Date().toISOString(),
        engine: 'nanojason-enhanced',
        seriesId: 'consistency-enhanced',
        imageIndex,
      },
    }
  }

  validateJasonPrompt(jasonString: string): {
    valid: boolean
    errors: string[]
    warnings: string[]
  } {
    const errors: string[] = []
    const warnings: string[] = []

    try {
      const prompt = this.parseJasonPrompt(jasonString)
      
      if (!prompt) {
        errors.push('Invalid JSON format')
        return { valid: false, errors, warnings }
      }

      // Validate required fields
      if (!prompt.prompt) {
        errors.push('Prompt field is required')
      }

      // Validate style
      const validStyles = ['realistic', 'anime', 'cartoon', 'fantasy', 'cyberpunk', 'artistic']
      if (prompt.style && !validStyles.includes(prompt.style)) {
        warnings.push(`Style "${prompt.style}" is not standard. Recommended: ${validStyles.join(', ')}`)
      }

      // Validate mood
      const validMoods = ['happy', 'sad', 'angry', 'peaceful', 'mysterious', 'epic', 'wonderful', 'neutral']
      if (prompt.mood && !validMoods.includes(prompt.mood)) {
        warnings.push(`Mood "${prompt.mood}" is not standard. Recommended: ${validMoods.join(', ')}`)
      }

      // Check for consistency if multiple prompts
      if (Array.isArray(prompt.characters) && prompt.characters.length > 3) {
        warnings.push('More than 3 characters may reduce consistency across images')
      }

    } catch (error) {
      errors.push(`Validation error: ${error instanceof Error ? error.message : 'Unknown error'}`)
    }

    return {
      valid: errors.length === 0,
      errors,
      warnings,
    }
  }

  optimizeForService(jasonPrompt: JasonPrompt, targetService: 'nanojason' | 'nanobanana' | 'openai' | 'midjourney'): JasonPrompt {
    const optimized = { ...jasonPrompt }

    // Service-specific optimizations
    switch (targetService) {
      case 'nanobanana':
        // NanoBanana-specific optimizations
        optimized.consistency = {
          ...optimized.consistency,
          characterFeatures: {
            ...optimized.consistency?.characterFeatures,
            style: 'consistent',
            quality: 'high',
          },
        }
        break

      case 'openai':
        // OpenAI DALL-E specific optimizations
        if (optimized.characters && optimized.characters.length > 1) {
          optimized.prompt += `, consistent character design across all images`
        }
        break

      case 'midjourney':
        // Midjourney specific optimizations
        optimized.consistency = {
          ...optimized.consistency,
          colorPalette: optimized.consistency?.colorPalette || ['vibrant', 'saturated'],
        }
        break

      default:
        // NanoJason optimizations
        break
    }

    return optimized
  }
}

export const jasonProcessor = new JasonProcessor()