import { useEffect, useState } from 'react'
import JSZip from 'jszip'
import ImageLightbox from './ImageLightbox'

const API_BASE = '/api'
const AUTH_TOKEN_KEY = 'amalfa_auth_token'

function authHeaders() {
  const token = typeof localStorage !== 'undefined' ? localStorage.getItem(AUTH_TOKEN_KEY) : null
  if (!token) return {}
  return { Authorization: `Bearer ${token}` }
}

function proxyImageUrl(url) {
  return url ? `${API_BASE}/proxy-image?url=${encodeURIComponent(url)}` : ''
}

function downloadImage(url, filename) {
  const a = document.createElement('a')
  a.href = proxyImageUrl(url) || url
  a.download = filename
  document.body.appendChild(a)
  a.click()
  a.remove()
}

async function fetchImageBlob(url) {
  if (!url) throw new Error('Missing image URL')
  try {
    const proxied = await fetch(proxyImageUrl(url))
    if (proxied.ok) return await proxied.blob()
  } catch (_) {}
  const direct = await fetch(url)
  if (!direct.ok) throw new Error('Failed to fetch image')
  return await direct.blob()
}

export default function Variations({ onLogout }) {
  const [imageModels, setImageModels] = useState([])
  const [selectedImageModel, setSelectedImageModel] = useState('nano-banana-2')
  const [aspectRatio, setAspectRatio] = useState('1:1')
  const [variationCount, setVariationCount] = useState(10)
  const [userPrompt, setUserPrompt] = useState('')
  const [winningImageUrl, setWinningImageUrl] = useState('')
  const [winningPreviewUrl, setWinningPreviewUrl] = useState('')
  const [uploading, setUploading] = useState(false)
  const [generating, setGenerating] = useState(false)
  const [progress, setProgress] = useState({ done: 0, total: 0 })
  const [results, setResults] = useState([])
  const [selected, setSelected] = useState([])
  const [downloading, setDownloading] = useState(false)
  const [error, setError] = useState(null)
  const [lightboxImage, setLightboxImage] = useState(null)

  useEffect(() => {
    fetch(`${API_BASE}/image-models`, { headers: authHeaders() })
      .then((r) => {
        if (r.status === 401) {
          localStorage.removeItem(AUTH_TOKEN_KEY)
          onLogout?.()
          return null
        }
        return r.ok ? r.json() : null
      })
      .then((data) => {
        if (!data) return
        setImageModels(data.models || [])
        if (data.default) setSelectedImageModel(data.default)
      })
      .catch(() => {})
  }, [onLogout])

  useEffect(() => {
    return () => {
      if (winningPreviewUrl) URL.revokeObjectURL(winningPreviewUrl)
    }
  }, [winningPreviewUrl])

  async function handleUpload(file) {
    if (!file) return
    if (winningPreviewUrl) URL.revokeObjectURL(winningPreviewUrl)
    setWinningPreviewUrl(URL.createObjectURL(file))
    setUploading(true)
    setError(null)
    try {
      const form = new FormData()
      form.append('file', file)
      const res = await fetch(`${API_BASE}/upload-reference`, {
        method: 'POST',
        headers: authHeaders(),
        body: form,
      })
      if (res.status === 401) {
        localStorage.removeItem(AUTH_TOKEN_KEY)
        onLogout?.()
        return
      }
      const data = await res.json().catch(() => ({}))
      if (!res.ok) throw new Error(data.detail || 'Upload failed')
      setWinningImageUrl(data.url || '')
    } catch (e) {
      setError(e.message || 'Upload failed')
    } finally {
      setUploading(false)
    }
  }

  async function handleGenerate() {
    if (!winningImageUrl) {
      setError('Upload a winning creative first.')
      return
    }
    setGenerating(true)
    setError(null)
    setResults([])
    setSelected([])
    setProgress({ done: 0, total: variationCount })
    try {
      const res = await fetch(`${API_BASE}/generate-variations/stream`, {
        method: 'POST',
        headers: { 'Content-Type': 'application/json', ...authHeaders() },
        body: JSON.stringify({
          image_url: winningImageUrl,
          n: variationCount,
          model_key: selectedImageModel,
          aspect_ratio: aspectRatio,
          user_prompt: userPrompt || undefined,
        }),
      })
      if (res.status === 401) {
        localStorage.removeItem(AUTH_TOKEN_KEY)
        onLogout?.()
        return
      }
      if (!res.ok) {
        const data = await res.json().catch(() => ({}))
        throw new Error(data.detail || 'Variation generation failed')
      }
      const reader = res.body.getReader()
      const decoder = new TextDecoder()
      let buffer = ''
      while (true) {
        const { done, value } = await reader.read()
        if (done) break
        buffer += decoder.decode(value, { stream: true })
        const chunks = buffer.split('\n\n')
        buffer = chunks.pop() || ''
        for (const chunk of chunks) {
          const dataLine = chunk.split('\n').find((l) => l.startsWith('data: '))
          if (!dataLine) continue
          try {
            const payload = JSON.parse(dataLine.slice(6))
            if (payload.event === 'result' && payload.data) {
              const rowId = `${payload.data.variation_id ?? 'v'}-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`
              setResults((prev) => [...prev, { ...payload.data, rowId }])
              setProgress((prev) => ({ ...prev, done: prev.done + 1 }))
            } else if (payload.event === 'error') {
              setError(payload.message || 'Variation generation failed')
            }
          } catch (_) {}
        }
      }
    } catch (e) {
      setError(e.message || 'Variation generation failed')
    } finally {
      setGenerating(false)
    }
  }

  function toggleSelect(rowId) {
    setSelected((prev) => (prev.includes(rowId) ? prev.filter((id) => id !== rowId) : [...prev, rowId]))
  }

  async function handleDownloadSelected() {
    const toDownload = results.filter((r) => r.image_url && selected.includes(r.rowId))
    if (!toDownload.length) return
    setDownloading(true)
    try {
      const zip = new JSZip()
      await Promise.all(
        toDownload.map(async (item, idx) => {
          const blob = await fetchImageBlob(item.image_url)
          const id = String(item.variation_id ?? idx + 1).padStart(2, '0')
          const slug = (item.concept_name || 'variation')
            .replace(/[^a-z0-9]+/gi, '-')
            .toLowerCase()
            .replace(/^-|-$/g, '') || 'variation'
          zip.file(`Amalfa-variation-${id}-${slug}.png`, blob)
        })
      )
      const blob = await zip.generateAsync({ type: 'blob' })
      const a = document.createElement('a')
      a.href = URL.createObjectURL(blob)
      a.download = 'Amalfa-variations-selected.zip'
      a.click()
      URL.revokeObjectURL(a.href)
    } catch (e) {
      setError(e.message || 'Failed to prepare ZIP')
    } finally {
      setDownloading(false)
    }
  }

  return (
    <section className="card variations-card">
      {lightboxImage && (
        <ImageLightbox
          src={lightboxImage.src}
          alt={lightboxImage.alt}
          onClose={() => setLightboxImage(null)}
        />
      )}
      <h2>Winning Creative Variations</h2>
      <p className="gallery-desc">Upload your best-performing creative and generate multiple fresh variations.</p>
      {error && <p className="error">{error}</p>}

      <div className="variations-controls">
        <label>
          <span>Winning creative image</span>
          <input
            type="file"
            accept="image/png,image/jpeg,image/webp"
            onChange={(e) => handleUpload(e.target.files?.[0])}
            disabled={uploading || generating}
          />
        </label>
        <label>
          <span>User prompt (optional)</span>
          <input
            type="text"
            value={userPrompt}
            onChange={(e) => setUserPrompt(e.target.value)}
            placeholder="e.g. Make it moodier, cinematic lighting, more close-up angles"
            disabled={generating}
          />
        </label>
        <label>
          <span>How many variations</span>
          <input
            type="range"
            min="1"
            max="30"
            value={variationCount}
            onChange={(e) => setVariationCount(Number(e.target.value))}
            disabled={generating}
          />
          <strong>{variationCount}</strong>
        </label>
        <label>
          <span>Image model</span>
          <select
            value={selectedImageModel}
            onChange={(e) => setSelectedImageModel(e.target.value)}
            disabled={generating}
          >
            {imageModels.map((m) => (
              <option key={m.key} value={m.key}>
                {m.label || m.key}
              </option>
            ))}
          </select>
        </label>
        <label>
          <span>Aspect ratio</span>
          <select value={aspectRatio} onChange={(e) => setAspectRatio(e.target.value)} disabled={generating}>
            <option value="1:1">1:1</option>
            <option value="16:9">16:9</option>
            <option value="9:16">9:16</option>
          </select>
        </label>
      </div>

      {winningImageUrl && (
        <div className="variations-winning-preview">
          <img src={winningPreviewUrl || winningImageUrl} alt="Winning creative" />
        </div>
      )}

      <div className="variations-actions">
        <button type="button" className="btn-run" disabled={generating || uploading || !winningImageUrl} onClick={handleGenerate}>
          {generating ? 'Generating…' : `Generate ${variationCount} Variations`}
        </button>
        {generating && <span className="gallery-item-date">Progress: {progress.done}/{progress.total}</span>}
      </div>

      {results.length > 0 && (
        <>
          <div className="gallery-toolbar">
            <label className="gallery-select-all">
              <input
                type="checkbox"
                checked={selected.length === results.length && results.length > 0}
                onChange={(e) => (e.target.checked ? setSelected(results.map((r) => r.rowId)) : setSelected([]))}
              />
              Select all
            </label>
            <button
              type="button"
              className="btn-download-zip"
              disabled={downloading || selected.length === 0}
              onClick={handleDownloadSelected}
            >
              {downloading ? 'Preparing…' : `Download selected (${selected.length})`}
            </button>
          </div>
          <div className="gallery-grid">
          {results.map((item, idx) => (
            <div className="gallery-item" key={item.rowId || `${item.variation_id || idx}-${idx}`}>
              <div className="gallery-item-img-wrap">
                {item.image_url ? (
                  <img
                    src={proxyImageUrl(item.image_url)}
                    alt={item.concept_name || `Variation ${idx + 1}`}
                    className="gallery-item-img img-expandable"
                    onClick={() =>
                      setLightboxImage({
                        src: proxyImageUrl(item.image_url),
                        alt: item.concept_name || `Variation ${idx + 1}`,
                      })
                    }
                  />
                ) : (
                  <div className="gallery-item-placeholder">Failed</div>
                )}
                <label className="gallery-item-checkbox">
                  <input
                    type="checkbox"
                    checked={selected.includes(item.rowId)}
                    onChange={() => toggleSelect(item.rowId)}
                  />
                  <span>Select</span>
                </label>
              </div>
              <div className="gallery-item-footer">
                <p className="gallery-item-concept">#{item.variation_id || idx + 1} {item.concept_name || 'Variation'}</p>
                {item.error ? (
                  <p className="error">{item.error}</p>
                ) : (
                  <button
                    type="button"
                    className="btn-gallery-download-one"
                    onClick={() => downloadImage(item.image_url, `variation-${item.variation_id || idx + 1}.png`)}
                  >
                    Download
                  </button>
                )}
              </div>
            </div>
          ))}
        </div>
        </>
      )}
    </section>
  )
}
