// Ollama Cloud API Client - For AI-powered story generation
// https://docs.ollama.com/cloud
import { sanitizeApiKey } from '@/utils/api-utils'

export interface OllamaChatRequest {
  model: string
  messages: Array<{
    role: 'system' | 'user' | 'assistant'
    content: string
  }>
  stream?: boolean
  options?: {
    temperature?: number
    top_p?: number
    max_tokens?: number
  }
}

export interface OllamaChatResponse {
  model: string
  created_at: string
  message: {
    role: string
    content: string
  }
  done: boolean
  total_duration?: number
  load_duration?: number
  prompt_eval_count?: number
  prompt_eval_duration?: number
  eval_count?: number
  eval_duration?: number
}

export interface OllamaModel {
  name: string
  size: string
  digest: string
  modified_at: string
}

export interface OllamaListResponse {
  models: OllamaModel[]
}

export class OllamaClient {
  private apiKey: string | null = null
  private baseURL: string
  private defaultModel = 'gpt-oss:120b-cloud' // Free cloud model

  constructor(apiKey?: string) {
    this.apiKey = sanitizeApiKey(apiKey) || process.env.OLLAMA_API_KEY || null
    this.baseURL = 'https://ollama.com'
  }

  

  // Check if API key is available
  isAvailable(): boolean {
    return !!this.apiKey
  }

  // List available models
  async listModels(): Promise<OllamaModel[]> {
    if (!this.isAvailable()) {
      throw new Error('Ollama API key not available')
    }

    const response = await fetch(`${this.baseURL}/api/tags`, {
      method: 'GET',
      headers: {
        'Authorization': `Bearer ${this.apiKey || ''}`,
        'Content-Type': 'application/json',
      },
    })

    if (!response.ok) {
      throw new Error(`Failed to list models: ${response.statusText}`)
    }

    const data: OllamaListResponse = await response.json()
    return data.models
  }

  // Generate chat completion
  async chat(request: OllamaChatRequest): Promise<string> {
    if (!this.isAvailable()) {
      throw new Error('Ollama API key not available')
    }

    const response = await fetch(`${this.baseURL}/api/chat`, {
      method: 'POST',
      headers: {
        'Authorization': `Bearer ${this.apiKey || ''}`,
        'Content-Type': 'application/json',
      },
      body: JSON.stringify({
        model: request.model || this.defaultModel,
        messages: request.messages,
        stream: false, // We'll handle streaming later
        options: {
          temperature: request.options?.temperature || 0.7,
          top_p: request.options?.top_p || 0.9,
          max_tokens: request.options?.max_tokens || 1500,
          ...request.options,
        },
      }),
    })

    if (!response.ok) {
      throw new Error(`Ollama chat failed: ${response.statusText}`)
    }

    if (request.stream) {
      // Handle streaming response
      return this.handleStreamResponse(response)
    } else {
      // Handle non-streaming response
      const data: OllamaChatResponse = await response.json()
      return data.message.content
    }
  }

  // Generate story series with narrative progression
  async generateStorySeries(
    basePrompt: string,
    options: {
      imageCount?: number
      style?: string
      mood?: string
      includeCharacters?: boolean
      includeItems?: boolean
    } = {}
  ): Promise<{
    title: string
    description: string
    prompts: string[]
    narrativeProgression: string[]
    characters: string[]
    items: string[]
    style: string
    mood: string
  }> {
    const imageCount = Math.min(options.imageCount || 5, 30) // Max 30 images
    
    const systemPrompt = `Generate ${imageCount} creative and diverse series ideas for visual storytelling based on the user's interest: "${basePrompt}"

Each idea should be:
1. Engaging and visually rich
2. Suitable for image series (5-30 images)
3. Different genres and styles
4. Have strong narrative potential
5. Appeal to creators and storytellers

Return as a JSON array of strings:
["Idea 1 title and brief description", "Idea 2 title and brief description", ...]

Focus on variety: fantasy, sci-fi, slice of life, adventure, mystery, etc.`

    try {
      const response = await this.chat({
        model: this.defaultModel,
        messages: [
          {
            role: 'system',
            content: systemPrompt
          },
          {
            role: 'user',
            content: `Generate ${imageCount} series ideas about ${basePrompt}`
          }
        ],
        options: {
          temperature: 0.8, // Higher creativity for stories
          max_tokens: 2000,
        },
      })

      // Parse JSON response
      const storyData = JSON.parse(response)
      
      return {
        title: storyData.title || 'Untitled Story',
        description: storyData.description || basePrompt,
        prompts: Array.isArray(storyData.prompts) ? storyData.prompts : [basePrompt],
        narrativeProgression: Array.isArray(storyData.narrativeProgression) ? storyData.narrativeProgression : ['Beginning', 'Middle', 'End'],
        characters: Array.isArray(storyData.characters) ? storyData.characters : [],
        items: Array.isArray(storyData.items) ? storyData.items : [],
        style: storyData.style || options.style || 'fantasy',
        mood: storyData.mood || options.mood || 'wonderful',
      }
    } catch (error) {
      console.error('Failed to generate story with Ollama:', error)
      
      // Fallback to basic structure if AI fails
      return this.generateFallbackStory(basePrompt, options, imageCount)
    }
  }

  // Fallback story generation without AI
  private generateFallbackStory(basePrompt: string, options: any, imageCount: number) {
    const stages = this.generateBasicProgression(imageCount)
    
    return {
      title: `${options.style || 'Fantasy'} Adventure`,
      description: basePrompt,
      prompts: stages.map((stage, index) => 
        `${basePrompt} - ${stage} (Scene ${index + 1} of ${imageCount})`
      ),
      narrativeProgression: stages,
      characters: options.includeCharacters !== false ? ['hero', 'guide', 'mystical being'] : [],
      items: options.includeItems !== false ? ['magical artifact', 'ancient map', 'enchanted weapon'] : [],
      style: options.style || 'fantasy',
      mood: options.mood || 'wonderful',
    }
  }

  private generateBasicProgression(imageCount: number): string[] {
    if (imageCount <= 3) {
      return [
        'Introduction and setting the scene',
        'Discovery and rising action',
        'Climax and resolution'
      ]
    } else if (imageCount <= 5) {
      return [
        'Introduction',
        'Rising action',
        'Midpoint',
        'Climax',
        'Resolution and aftermath'
      ]
    } else if (imageCount <= 8) {
      return [
        'Introduction',
        'Setup',
        'Rising action 1',
        'Rising action 2', 
        'Midpoint',
        'Climax',
        'Falling action',
        'Conclusion'
      ]
    } else {
      // For longer series, generate more detailed progression
      const stages = ['Introduction', 'Setup']
      for (let i = 2; i <= imageCount; i++) {
        stages.push(`Development ${i-1}`)
      }
      return stages.slice(0, imageCount)
    }
  }

  // Handle streaming response
  private async handleStreamResponse(response: Response): Promise<string> {
    const reader = response.body?.getReader()
    if (!reader) {
      throw new Error('Streaming not supported')
    }

    const decoder = new TextDecoder()
    let fullContent = ''

    try {
      while (true) {
        const { done, value } = await reader.read()
        if (done) break

        const chunk = decoder.decode(value, { stream: true })
        const lines = chunk.split('\n').filter(line => line.trim())

        for (const line of lines) {
          if (line.startsWith('data: ')) {
            try {
              const data = JSON.parse(line.slice(6))
              if (data.message?.content) {
                fullContent += data.message.content
              }
            } catch (e) {
              // Ignore malformed JSON chunks
            }
          }
        }
      }
    } finally {
      reader.releaseLock()
    }

    return fullContent
  }

  // Get API key info
  getApiKeyInfo(): { isSet: boolean; source: string } {
    if (this.apiKey) {
      return {
        isSet: true,
        source: 'constructor'
      }
    }
    
    // Check localStorage
    const storedKey = typeof window !== 'undefined' ? localStorage.getItem('ollama_api_key') : null
    if (storedKey) {
      return {
        isSet: true,
        source: 'localStorage'
      }
    }

    return {
      isSet: false,
      source: 'none'
    }
  }

  // Set API key with sanitization
  setApiKey(apiKey: string, persist: boolean = false): void {
    const sanitizedKey = sanitizeApiKey(apiKey)
    if (!sanitizedKey) {
      console.error('Invalid API key format')
      return
    }
    
    this.apiKey = sanitizedKey
    
    if (persist && typeof window !== 'undefined') {
      localStorage.setItem('ollama_api_key', sanitizedKey)
    }
  }

  // Clear API key
  clearApiKey(): void {
    this.apiKey = null
    if (typeof window !== 'undefined') {
      localStorage.removeItem('ollama_api_key')
    }
  }
}

// Create default instance
export const ollamaClient = new OllamaClient()

// Available cloud models
export const OLLAMA_CLOUD_MODELS = {
  'gpt-oss:120b-cloud': 'GPT-4 Turbo (120B) - Good balance of speed and quality',
  'gpt-oss:137b-cloud': 'GPT-4 Large (137B) - Higher quality, slower',
  'gpt-oss:78b-cloud': 'GPT-3.5 Turbo (78B) - Fastest responses',
  'gpt-oss:34b-cloud': 'GPT-3.5 (34B) - Most economical',
  'llama3:70b-cloud': 'Llama 3 (70B) - Open source alternative',
  'llama3:8b-cloud': 'Llama 3 (8B) - Fast and efficient',
} as const