// Qwen API Client - Based on Qwen Code implementation
import { createAuthHeader } from '@/utils/api-utils'
// Provides 2,000 free daily requests with 60 requests/minute rate limit

export interface QwenAuthConfig {
  clientId: string
  clientSecret: string
  redirectUri: string
}

export interface QwenTokenResponse {
  access_token: string
  refresh_token: string
  expires_in: number
  token_type: string
  scope: string
}

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

export interface QwenChatResponse {
  id: string
  object: string
  created: number
  model: string
  choices: Array<{
    index: number
    message: {
      role: string
      content: string
    }
    finish_reason: string
  }>
  usage: {
    prompt_tokens: number
    completion_tokens: number
    total_tokens: number
  }
}

export interface QwenImageRequest {
  model: string
  prompt: string
  n?: number
  size?: string
  quality?: string
  style?: string
}

export interface QwenImageResponse {
  created: number
  data: Array<{
    url: string
    revised_prompt?: string
  }>
}

export class QwenAPIClient {
  private accessToken: string | null = null
  private refreshToken: string | null = null
  private tokenExpiry: number = 0
  private baseURL = 'https://dashscope.aliyuncs.com/api/v1'

  constructor(private config: QwenAuthConfig) {}

  // OAuth Flow
  async authenticate(): Promise<string> {
    // Generate PKCE parameters for security
    const codeVerifier = this.generateCodeVerifier()
    const codeChallenge = await this.generateCodeChallenge(codeVerifier)
    const state = this.generateState()

    // Store PKCE parameters for callback verification
    sessionStorage.setItem('qwen_code_verifier', codeVerifier)
    sessionStorage.setItem('qwen_oauth_state', state)

    // Build OAuth URL
    const params = new URLSearchParams({
      client_id: this.config.clientId,
      redirect_uri: this.config.redirectUri,
      response_type: 'code',
      scope: 'api_access',
      state: state,
      code_challenge: codeChallenge,
      code_challenge_method: 'S256'
    })

    const oauthUrl = `https://qwen.ai/oauth/authorize?${params.toString()}`
    
    // Redirect to OAuth provider
    window.location.href = oauthUrl
    
    return new Promise((resolve) => {
      // This will be resolved in the callback handling
      window.addEventListener('message', (event) => {
        if (event.data.type === 'qwen_auth_success') {
          resolve(event.data.token)
        }
      })
    })
  }

  // Exchange authorization code for access token
  async exchangeCodeForToken(code: string, codeVerifier: string): Promise<QwenTokenResponse> {
    const response = await fetch(`${this.baseURL}/oauth/token`, {
      method: 'POST',
      headers: {
        'Content-Type': 'application/x-www-form-urlencoded',
        'Accept': 'application/json',
      },
      body: new URLSearchParams({
        grant_type: 'authorization_code',
        client_id: this.config.clientId,
        client_secret: this.config.clientSecret,
        code: code,
        code_verifier: codeVerifier,
        redirect_uri: this.config.redirectUri,
      }),
    })

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

    const tokenData: QwenTokenResponse = await response.json()
    
    // Store token information
    this.accessToken = tokenData.access_token
    this.refreshToken = tokenData.refresh_token
    this.tokenExpiry = Date.now() + (tokenData.expires_in * 1000)

    // Store in localStorage for persistence
    localStorage.setItem('qwen_access_token', tokenData.access_token)
    localStorage.setItem('qwen_refresh_token', tokenData.refresh_token)
    localStorage.setItem('qwen_token_expiry', this.tokenExpiry.toString())

    return tokenData
  }

  // Refresh access token
  async refreshAccessToken(): Promise<QwenTokenResponse> {
    if (!this.refreshToken) {
      throw new Error('No refresh token available')
    }

    const response = await fetch(`${this.baseURL}/oauth/token`, {
      method: 'POST',
      headers: {
        'Content-Type': 'application/x-www-form-urlencoded',
        'Accept': 'application/json',
      },
      body: new URLSearchParams({
        grant_type: 'refresh_token',
        client_id: this.config.clientId,
        client_secret: this.config.clientSecret,
        refresh_token: this.refreshToken,
      }),
    })

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

    const tokenData: QwenTokenResponse = await response.json()
    
    // Update stored token information
    this.accessToken = tokenData.access_token
    this.refreshToken = tokenData.refresh_token
    this.tokenExpiry = Date.now() + (tokenData.expires_in * 1000)

    localStorage.setItem('qwen_access_token', tokenData.access_token)
    localStorage.setItem('qwen_refresh_token', tokenData.refresh_token)
    localStorage.setItem('qwen_token_expiry', this.tokenExpiry.toString())

    return tokenData
  }

  // Get valid access token
  async getAccessToken(): Promise<string> {
    // Check if token exists and is not expired
    if (!this.accessToken || Date.now() >= this.tokenExpiry) {
      // Try to refresh token
      await this.refreshAccessToken()
    }

    if (!this.accessToken) {
      throw new Error('Unable to obtain access token')
    }

    return this.accessToken
  }

  // Chat completion API
  async chatCompletion(request: QwenChatRequest): Promise<QwenChatResponse> {
    const token = await this.getAccessToken()

    const response = await fetch(`${this.baseURL}/services/aigc/text-generation/generation`, {
      method: 'POST',
      headers: {
        'Authorization': createAuthHeader(token),
        'Content-Type': 'application/json',
      },
      body: JSON.stringify({
        model: request.model,
        input: {
          messages: request.messages,
        },
        parameters: {
          max_tokens: request.max_tokens || 1500,
          temperature: request.temperature || 0.7,
          top_p: request.top_p || 0.8,
        },
      }),
    })

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

    const data = await response.json()
    
    return {
      id: data.request_id,
      object: 'chat.completion',
      created: Date.now() / 1000,
      model: request.model,
      choices: data.output?.choices || [],
      usage: {
        prompt_tokens: data.usage?.input_tokens || 0,
        completion_tokens: data.usage?.output_tokens || 0,
        total_tokens: data.usage?.total_tokens || 0,
      },
    }
  }

  // Image generation API
  async generateImages(request: QwenImageRequest): Promise<QwenImageResponse> {
    const token = await this.getAccessToken()

    const response = await fetch(`${this.baseURL}/services/aigc/text2image/image-synthesis`, {
      method: 'POST',
      headers: {
        'Authorization': createAuthHeader(token),
        'Content-Type': 'application/json',
      },
      body: JSON.stringify({
        model: request.model || 'qwen-vl-plus',
        input: {
          prompt: request.prompt,
        },
        parameters: {
          n: request.n || 1,
          size: request.size || '1024x1024',
          quality: request.quality || 'standard',
          style: request.style || 'vivid',
        },
      }),
    })

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

    const data = await response.json()
    
    return {
      created: Date.now() / 1000,
      data: data.output?.results?.map((result: any) => ({
        url: result.url,
        revised_prompt: result.prompt,
      })) || [],
    }
  }

  // Rate limit checking
  async checkRateLimit(): Promise<{ remaining: number; resetTime: number }> {
    try {
      const token = await this.getAccessToken()
      
      // This would normally be parsed from response headers
      // For demo, we'll simulate the 2,000 daily limit
      const dailyLimit = 2000
      const usedToday = Math.floor(Math.random() * dailyLimit)
      const remaining = dailyLimit - usedToday
      const resetTime = Math.floor(Date.now() / 1000) + (24 * 3600) // Next midnight

      return {
        remaining,
        resetTime,
      }
    } catch (error) {
      console.error('Rate limit check failed:', error)
      return {
        remaining: 2000,
        resetTime: Math.floor(Date.now() / 1000) + (24 * 3600),
      }
    }
  }

  // Helper methods
  private generateCodeVerifier(): string {
    const array = new Uint8Array(32)
    crypto.getRandomValues(array)
    return btoa(String.fromCharCode(...array))
      .replace(/\+/g, '-')
      .replace(/\//g, '_')
      .replace(/=/g, '')
  }

  private async generateCodeChallenge(verifier: string): Promise<string> {
    const encoder = new TextEncoder()
    const data = encoder.encode(verifier)
    const digest = await crypto.subtle.digest('SHA-256', data)
    return btoa(String.fromCharCode(...new Uint8Array(digest)))
      .replace(/\+/g, '-')
      .replace(/\//g, '_')
      .replace(/=/g, '')
  }

  private generateState(): string {
    return Math.random().toString(36).substring(2, 15)
  }

  // Initialize from stored tokens
  initializeFromStorage(): void {
    this.accessToken = localStorage.getItem('qwen_access_token')
    this.refreshToken = localStorage.getItem('qwen_refresh_token')
    const expiry = localStorage.getItem('qwen_token_expiry')
    this.tokenExpiry = expiry ? parseInt(expiry) : 0
  }

  // Logout
  logout(): void {
    this.accessToken = null
    this.refreshToken = null
    this.tokenExpiry = 0
    
    localStorage.removeItem('qwen_access_token')
    localStorage.removeItem('qwen_refresh_token')
    localStorage.removeItem('qwen_token_expiry')
    localStorage.removeItem('qwen_authenticated')
  }
}

// Default models available
export const QWEN_MODELS = {
  TEXT: 'qwen-turbo',
  CHAT: 'qwen-plus',
  VISION: 'qwen-vl-plus',
  IMAGE: 'qwen-vl-plus',
} as const

// Rate limits
export const QWEN_LIMITS = {
  FREE_DAILY: 2000,
  FREE_MINUTE: 60,
  PRO_DAILY: 50000,
  PRO_MINUTE: 500,
} as const