import { ref, reactive, onUnmounted } from 'vue'

const API_BASE = import.meta.env.VITE_SKG_API_BASE || '/api'

const apiUrl = (path) => `${API_BASE}${path.startsWith('/') ? '' : '/'}${path}`

const toAssetUrl = (path) => {
  if (!path) return ''
  if (/^(https?:|blob:|data:)/i.test(path)) return path
  return apiUrl(path)
}

const parseApiError = async (response, fallback) => {
  const text = await response.text().catch(() => '')
  try {
    const parsed = JSON.parse(text)
    return parsed?.detail || parsed?.error || fallback
  } catch {
    return text || fallback
  }
}

const requestJson = async (path, init = {}) => {
  const response = await fetch(apiUrl(path), {
    ...init,
    headers: {
      ...(init.body instanceof FormData ? {} : { 'Content-Type': 'application/json' }),
      ...(init.headers || {})
    }
  })
  if (!response.ok) {
    throw new Error(await parseApiError(response, `${path} ${response.status}`))
  }
  return response.json()
}

const dataUrlToFile = (dataUrl, filename = 'reference.jpg') => {
  const [meta, payload] = dataUrl.split(',')
  const mime = /data:([^;]+)/.exec(meta)?.[1] || 'image/jpeg'
  const binary = atob(payload || '')
  const bytes = new Uint8Array(binary.length)
  for (let i = 0; i < binary.length; i += 1) bytes[i] = binary.charCodeAt(i)
  return new File([bytes], filename, { type: mime })
}

const imageSourceToFile = async (source, filename = 'reference.jpg') => {
  if (!source) return null
  if (source instanceof File) return source
  if (typeof source !== 'string') return null
  if (source.startsWith('data:')) return dataUrlToFile(source, filename)
  const url = source.startsWith('/jobs/') ? apiUrl(source) : source
  const response = await fetch(url)
  if (!response.ok) throw new Error(`读取参考图失败 ${response.status}`)
  const blob = await response.blob()
  return new File([blob], filename, { type: blob.type || 'image/jpeg' })
}

const createCreativeImageJob = async (file = null) => {
  if (file) {
    const form = new FormData()
    form.append('file', file)
    return requestJson('/creative/jobs/image', { method: 'POST', body: form })
  }
  return requestJson('/creative/jobs/image', { method: 'POST', body: JSON.stringify({}) })
}

const uploadReferenceFrame = async (jobId, file) => {
  const form = new FormData()
  form.append('file', file)
  return requestJson(`/jobs/${jobId}/frames/upload`, { method: 'POST', body: form })
}

const newestGeneratedImage = (job, frameIdx = 0) => {
  const frame = (job.frames || []).find(item => item.index === frameIdx) || job.frames?.[0]
  return [...(frame?.generated_images || [])].sort((a, b) => (b.created_at || 0) - (a.created_at || 0))[0]
}

const newestGeneratedVideo = (job) => (
  [...(job.generated_videos || [])].sort((a, b) => (b.created_at || 0) - (a.created_at || 0))[0]
)

const normalizeVideoSize = (value) => {
  const raw = String(value || '').trim().toLowerCase()
  const map = {
    '9:16': '720x1280',
    '9x16': '720x1280',
    'vertical': '720x1280',
    'portrait': '720x1280',
    '16:9': '1280x720',
    '16x9': '1280x720',
    'horizontal': '1280x720',
    'landscape': '1280x720',
    '1:1': '1024x1024',
    '1x1': '1024x1024',
    '3:4': '960x1280',
    '3x4': '960x1280'
  }
  if (/^\d+x\d+$/.test(raw)) return raw
  return map[raw] || '720x1280'
}

export const useApiState = () => {
  const loading = ref(false)
  const error = ref(null)
  const status = ref('idle')

  const reset = () => {
    loading.value = false
    error.value = null
    status.value = 'idle'
  }
  const setLoading = (isLoading) => {
    loading.value = isLoading
    status.value = isLoading ? 'running' : status.value
  }
  const setError = (err) => {
    error.value = err
    status.value = 'error'
    loading.value = false
  }
  const setSuccess = () => {
    status.value = 'success'
    loading.value = false
    error.value = null
  }

  return { loading, error, status, reset, setLoading, setError, setSuccess }
}

export const useChat = () => {
  const { loading, error, status, reset, setLoading, setError, setSuccess } = useApiState()
  const messages = ref([])
  const currentResponse = ref('')
  let stopped = false

  const send = async (content) => {
    setLoading(true)
    stopped = false
    try {
      const response = await requestJson('/creative/copy', {
        method: 'POST',
        body: JSON.stringify({ goal: content, seconds: 15 })
      })
      const variant = response.variants?.[0]
      const result = variant?.image_prompt_en || variant?.video_prompt_en || content
      if (!stopped) {
        currentResponse.value = result
        messages.value.push({ role: 'user', content })
        messages.value.push({ role: 'assistant', content: result })
      }
      setSuccess()
      return result
    } catch (err) {
      setError(err)
      throw err
    }
  }

  const stop = () => {
    stopped = true
  }
  const clear = () => {
    messages.value = []
    currentResponse.value = ''
    reset()
  }
  onUnmounted(() => stop())
  return { loading, error, status, messages, currentResponse, send, stop, clear, reset }
}

export const useImageGeneration = () => {
  const { loading, error, status, reset, setLoading, setError, setSuccess } = useApiState()
  const images = ref([])
  const currentImage = ref(null)

  const generate = async (params) => {
    setLoading(true)
    images.value = []
    currentImage.value = null
    try {
      const refs = Array.isArray(params.image) ? params.image : (params.image ? [params.image] : [])
      const firstRef = refs[0] ? await imageSourceToFile(refs[0], 'image-reference.jpg') : null
      const job = await createCreativeImageJob(firstRef)
      const updated = await requestJson(`/jobs/${job.id}/frames/0/generate`, {
        method: 'POST',
        body: JSON.stringify({
          prompt: params.prompt || '',
          model: params.model || 'auto',
          size: params.size || '1024x1536',
          mode: firstRef ? 'edit' : 'text'
        })
      })
      const generated = newestGeneratedImage(updated, 0)
      if (!generated?.url) throw new Error('图片生成完成但未返回地址')
      const result = [{ ...generated, url: toAssetUrl(generated.url), jobId: updated.id, frameIdx: 0 }]
      images.value = result
      currentImage.value = result[0]
      setSuccess()
      return result
    } catch (err) {
      setError(err)
      throw err
    }
  }

  return { loading, error, status, images, currentImage, generate, reset }
}

export const useVideoGeneration = () => {
  const { loading, error, status, reset, setLoading, setError, setSuccess } = useApiState()
  const video = ref(null)
  const taskId = ref(null)
  const progress = reactive({ attempt: 0, maxAttempts: 180, percentage: 0 })

  const createVideoTaskOnly = async (params) => {
    setLoading(true)
    try {
      const firstFile = params.first_frame_image ? await imageSourceToFile(params.first_frame_image, 'first-frame.jpg') : null
      let job = await createCreativeImageJob(firstFile)
      let lastFrameIdx = null
      if (params.last_frame_image) {
        const lastFile = await imageSourceToFile(params.last_frame_image, 'last-frame.jpg')
        if (lastFile) {
          job = await uploadReferenceFrame(job.id, lastFile)
          lastFrameIdx = Math.max(...(job.frames || []).map(frame => frame.index))
        }
      }
      const updated = await requestJson(`/jobs/${job.id}/frames/0/storyboard/video`, {
        method: 'POST',
        body: JSON.stringify({
          prompt: params.prompt || '',
          duration: Number(params.dur || params.duration || params.seconds || 10),
          count: 1,
          first_image: firstFile ? { kind: 'keyframe', frame_idx: 0 } : null,
          last_image: lastFrameIdx !== null ? { kind: 'keyframe', frame_idx: lastFrameIdx } : null,
          model: params.model || 'seedance',
          size: normalizeVideoSize(params.ratio || params.size)
        })
      })
      const created = newestGeneratedVideo(updated)
      if (!created?.id) throw new Error('视频任务已提交但未返回任务编号')
      const id = `skg:${updated.id}:${created.id}`
      taskId.value = id
      status.value = 'polling'
      setSuccess()
      return { taskId: id }
    } catch (err) {
      setError(err)
      throw err
    }
  }

  const pollVideoTask = async (pollTaskId, onProgress = () => {}) => {
    const match = /^skg:([^:]+):([^:]+)$/.exec(String(pollTaskId || ''))
    if (!match) throw new Error('未知视频任务类型')
    const [, jobId, videoId] = match
    const maxAttempts = 180
    const interval = 5000

    for (let i = 0; i < maxAttempts; i += 1) {
      const job = await requestJson(`/jobs/${jobId}`, { method: 'GET' })
      const item = (job.generated_videos || []).find(v => v.id === videoId)
      if (!item) throw new Error('视频任务不存在')
      const percentage = item.progress || Math.min(Math.round((i / maxAttempts) * 100), 98)
      onProgress(i + 1, percentage)
      progress.attempt = i + 1
      progress.percentage = percentage
      if (item.status === 'completed') {
        const result = { ...item, url: toAssetUrl(item.url || `/jobs/${jobId}/storyboard-videos/${videoId}.mp4`) }
        video.value = result
        setSuccess()
        return result
      }
      if (item.status === 'failed') {
        throw new Error(item.error || '视频生成失败')
      }
      await new Promise(resolve => setTimeout(resolve, interval))
    }
    throw new Error('视频生成超时')
  }

  const generate = async (params) => {
    const { taskId: newTaskId, url } = await createVideoTaskOnly(params)
    if (url) {
      video.value = { url }
      return video.value
    }
    return pollVideoTask(newTaskId)
  }

  return { loading, error, status, video, taskId, progress, generate, reset, createVideoTaskOnly, pollVideoTask }
}

export const useApi = () => {
  const chat = useChat()
  const image = useImageGeneration()
  const videoGen = useVideoGeneration()
  return { config: {}, chat, image, video: videoGen }
}
