import { NextResponse } from 'next/server'
import { Redis } from '@upstash/redis'
import { createClient } from '@supabase/supabase-js'
import { v4 as uuidv4 } from 'uuid'
import { aiRatelimit, getClientIp, checkRateLimit } from '@/lib/ratelimit'
import { sanitizePrompt } from '@/lib/validation'
import { getArchetypeById } from '@/data/archetypes'
import {
  buildPrimePrompt,
  PRIME_TIERS,
  PRIME_GRAINS,
  PRIME_RAINS,
  type PrimeTier,
  type PrimeGrain,
  type PrimeRain,
} from '@/lib/primePrompt'

export const runtime = 'nodejs'
export const dynamic = 'force-dynamic'

const MAX_FILE_MB = 10
const MAX_FILE_BYTES = MAX_FILE_MB * 1024 * 1024

// Lazy initialization to avoid issues with env vars at module load
function getRedis() {
  return new Redis({
    url: process.env.UPSTASH_REDIS_REST_URL!,
    token: process.env.UPSTASH_REDIS_REST_TOKEN!,
  })
}

function getSupabase() {
  return createClient(
    process.env.NEXT_PUBLIC_SUPABASE_URL!,
    process.env.SUPABASE_SERVICE_ROLE_KEY!
  )
}

function parseDataUri(dataUri: string): { mime: string; buffer: Buffer } | null {
  const match = dataUri.match(/^data:(image\/[a-zA-Z0-9+.-]+);base64,(.+)$/)
  if (!match) return null
  return { mime: match[1].toLowerCase(), buffer: Buffer.from(match[2], 'base64') }
}

function normalizeTier(input: string | null): PrimeTier | null {
  if (!input) return 'core'
  const value = input.toLowerCase().trim()
  return PRIME_TIERS.includes(value as PrimeTier) ? (value as PrimeTier) : null
}

function normalizeGrain(input: string | null): PrimeGrain | null {
  if (!input) return 'gritty'
  const value = input.toLowerCase().trim()
  return PRIME_GRAINS.includes(value as PrimeGrain) ? (value as PrimeGrain) : null
}

function normalizeRain(input: string | null): PrimeRain | null {
  if (!input) return 'light'
  const value = input.toLowerCase().trim()
  return PRIME_RAINS.includes(value as PrimeRain) ? (value as PrimeRain) : null
}

export async function POST(request: Request) {
  try {
    // Rate limiting
    const ip = getClientIp(request)
    const { success, error } = await checkRateLimit(aiRatelimit, ip)
    if (!success) return error

    // Parse JSON body
    let body
    try {
      body = await request.json()
    } catch {
      return NextResponse.json({ error: 'Invalid JSON body' }, { status: 400 })
    }

    const { image, tier, grain, rain, aura_color, archetype } = body

    // Validate image
    if (!image || typeof image !== 'string' || !image.startsWith('data:image/')) {
      return NextResponse.json({ error: 'Invalid image data' }, { status: 400 })
    }

    const parsed = parseDataUri(image)
    if (!parsed) {
      return NextResponse.json({ error: 'Invalid image data' }, { status: 400 })
    }
    if (!['image/png', 'image/jpeg', 'image/webp', 'image/jpg'].includes(parsed.mime)) {
      return NextResponse.json({ error: 'Unsupported image format' }, { status: 400 })
    }
    if (parsed.buffer.length > MAX_FILE_BYTES) {
      return NextResponse.json({ error: 'Image too large' }, { status: 400 })
    }

    // Normalize parameters
    const normalizedTier = normalizeTier(tier)
    const normalizedGrain = normalizeGrain(grain)
    const normalizedRain = normalizeRain(rain)

    if (!normalizedTier || !normalizedGrain || !normalizedRain) {
      return NextResponse.json({ error: 'Invalid parameters' }, { status: 400 })
    }

    const auraColor = sanitizePrompt(aura_color || 'void-silver').toLowerCase().trim() || 'void-silver'
    const archetypeId = archetype?.toString().toLowerCase().trim()
    const archetypeData = archetypeId ? getArchetypeById(archetypeId) : undefined

    // Build the prompt
    const { prompt } = buildPrimePrompt({
      tier: normalizedTier,
      auraColor,
      archetypeName: archetypeData?.name,
      archetypeModifier: archetypeData?.promptModifier,
      grain: normalizedGrain,
      rain: normalizedRain,
    })

    // Create job ID
    const jobId = uuidv4()

    // Upload image to Supabase storage (instead of storing in Redis)
    const filename = `input-${jobId}.png`
    const { error: uploadError } = await getSupabase().storage
      .from('gallery')
      .upload(filename, parsed.buffer, {
        contentType: 'image/png',
        cacheControl: '3600',
      })

    if (uploadError) {
      console.error('Upload error:', uploadError)
      return NextResponse.json({ error: `Failed to upload image: ${uploadError.message}` }, { status: 500 })
    }

    // Get the URL for the uploaded image
    const { data: urlData } = getSupabase().storage.from('gallery').getPublicUrl(filename)
    const inputImageUrl = urlData?.publicUrl

    if (!inputImageUrl) {
      return NextResponse.json({ error: 'Failed to get image URL' }, { status: 500 })
    }

    // Create job with URL instead of base64 (much smaller!)
    const job = {
      id: jobId,
      status: 'queued',
      inputImageUrl, // URL instead of base64
      prompt,
      tier: normalizedTier,
      grain: normalizedGrain,
      rain: normalizedRain,
      archetype: archetypeId || 'forged',
      createdAt: Date.now(),
    }

    // Store job in Redis (now much smaller - just metadata)
    await getRedis().hset(`job:${jobId}`, job)
    // Add to queue
    await getRedis().lpush('prime_jobs', jobId)

    // Return job ID immediately (fast response, no timeout)
    return NextResponse.json(
      {
        jobId,
        status: 'queued',
        statusUrl: `/api/prime-async/status/${jobId}`
      },
      { status: 202 }
    )
  } catch (error: unknown) {
    console.error('Enqueue error:', error)
    const message = error instanceof Error ? error.message : 'Failed to queue job'
    return NextResponse.json({ error: message }, { status: 500 })
  }
}
