import { GoogleGenAI, VideoGenerationReferenceType } from '@google/genai'
import { NextResponse } from 'next/server'
import { supabase } from '@/lib/supabase'

interface Exercise {
  name: string
  duration: number
}

interface GeneratedVideo {
  exerciseName: string
  videoType: 'exercise' | 'rest'
  videoUrl: string
  videoPath: string
  durationSeconds: number
}

async function pollOperation(ai: GoogleGenAI, operation: any): Promise<any> {
  while (!operation.done) {
    await new Promise(resolve => setTimeout(resolve, 10000))
    operation = await ai.operations.getVideosOperation({ operation })
  }
  return operation
}

async function uploadVideo(
  bucket: string,
  path: string,
  buffer: Buffer
): Promise<string> {
  const { error } = await supabase.storage
    .from(bucket)
    .upload(path, buffer, {
      contentType: 'video/mp4',
      upsert: true,
    })

  if (error) {
    throw new Error(`Failed to upload video: ${error.message}`)
  }

  const { data: { publicUrl } } = supabase.storage
    .from(bucket)
    .getPublicUrl(path)

  return publicUrl
}

async function getMimeTypeFromUrl(url: string): Promise<string> {
  try {
    const urlPath = new URL(url).pathname
    const extension = urlPath.split('.').pop()?.toLowerCase()
    switch (extension) {
      case 'png':
        return 'image/png'
      case 'jpg':
      case 'jpeg':
        return 'image/jpeg'
      case 'webp':
        return 'image/webp'
      case 'gif':
        return 'image/gif'
      default:
        return 'image/png'
    }
  } catch {
    return 'image/png'
  }
}

async function generateVideoWithReference(
  ai: GoogleGenAI,
  apiKey: string,
  prompt: string,
  avatarUrl: string,
  durationSeconds: number = 8
): Promise<{ uri: string; buffer: Buffer } | null> {
  // Fetch avatar image from URL and convert to base64
  const avatarResponse = await fetch(avatarUrl)
  const avatarBuffer = await avatarResponse.arrayBuffer()
  const avatarBase64 = Buffer.from(avatarBuffer).toString('base64')
  const mimeType = await getMimeTypeFromUrl(avatarUrl)

  const operation = await ai.models.generateVideos({
    model: 'veo-3.1-fast-generate-preview',
    prompt,
    config: {
      numberOfVideos: 1,
      aspectRatio: '16:9',
      resolution: '1080p',
      durationSeconds,
      referenceImages: [{
        image: {
          imageBytes: avatarBase64,
          mimeType,
        },
        referenceType: 'character' as any,
      }],
    },
  })

  const completedOperation = await pollOperation(ai, operation)
  const videoUri = completedOperation.response?.generatedVideos?.[0]?.video?.uri

  if (!videoUri) {
    return null
  }

  const response = await fetch(`${videoUri}&key=${apiKey}`)
  const arrayBuffer = await response.arrayBuffer()
  const videoBuffer = Buffer.from(arrayBuffer)

  return { uri: videoUri, buffer: videoBuffer }
}

async function extendVideo(
  ai: GoogleGenAI,
  apiKey: string,
  videoUri: string,
  prompt: string,
  durationSeconds: number = 8
): Promise<{ uri: string; buffer: Buffer } | null> {
  const operation = await ai.models.generateVideos({
    model: 'veo-3.1-fast-generate-preview',
    prompt,
    video: videoUri as any,
    config: {
      numberOfVideos: 1,
      durationSeconds,
    },
  })

  const completedOperation = await pollOperation(ai, operation)
  const newVideoUri = completedOperation.response?.generatedVideos?.[0]?.video?.uri

  if (!newVideoUri) {
    return null
  }

  const response = await fetch(`${newVideoUri}&key=${apiKey}`)
  const arrayBuffer = await response.arrayBuffer()
  const videoBuffer = Buffer.from(arrayBuffer)

  return { uri: newVideoUri, buffer: videoBuffer }
}

export async function POST(request: Request) {
  try {
    const { workoutId, trainerId, trainerAvatarUrl, exercises } = await request.json()

    if (!trainerAvatarUrl) {
      return NextResponse.json(
        { error: 'Trainer avatar URL is required' },
        { status: 400 }
      )
    }

    const apiKey = process.env.GEMINI_API_KEY
    if (!apiKey) {
      return NextResponse.json(
        { error: 'GEMINI_API_KEY not configured' },
        { status: 500 }
      )
    }

    const ai = new GoogleGenAI({ apiKey })
    const generatedVideos: GeneratedVideo[] = []

    for (const exercise of exercises) {
      const exerciseName = exercise.name

      console.log(`Processing exercise: ${exerciseName}`)

      const safeName = exerciseName.toLowerCase().replace(/[^a-z0-9]/g, '_')

      // 1. Generate 8s exercise video with avatar reference
      console.log(`Generating base exercise video for: ${exerciseName}`)
      const exercisePrompt = `A fitness trainer demonstrating ${exerciseName} exercise with correct form and technique. The person should be energetic and perform the exercise properly.`

      let exerciseVideo = await generateVideoWithReference(
        ai,
        apiKey,
        exercisePrompt,
        trainerAvatarUrl,
        8
      )

      if (!exerciseVideo) {
        console.error(`Failed to generate base exercise video for: ${exerciseName}`)
        continue
      }

      // 2. Extend exercise video to 22s (8s + 7s + 7s)
      console.log(`Extending exercise video for: ${exerciseName}`)

      const extendPrompt1 = `Continue the ${exerciseName} exercise motion seamlessly`
      let extended1 = await extendVideo(ai, apiKey, exerciseVideo.uri, extendPrompt1, 8)

      if (extended1) {
        const extendPrompt2 = `Continue the ${exerciseName} exercise motion seamlessly`
        const extended2 = await extendVideo(ai, apiKey, extended1.uri, extendPrompt2, 8)

        if (extended2) {
          exerciseVideo = extended2
        }
      }

      const exercisePath = `${trainerId}/${workoutId}/${safeName}.mp4`
      const exerciseUrl = await uploadVideo('trainer-videos', exercisePath, exerciseVideo.buffer)

      generatedVideos.push({
        exerciseName,
        videoType: 'exercise',
        videoUrl: exerciseUrl,
        videoPath: exercisePath,
        durationSeconds: 22,
      })

      console.log(`Exercise video uploaded: ${exerciseUrl}`)

      // 3. Generate 8s rest video with avatar reference
      console.log(`Generating rest video for: ${exerciseName}`)
      const restPrompt = `A fitness trainer resting, standing still, breathing calmly with arms at sides. The person looks relaxed.`

      const restVideo = await generateVideoWithReference(
        ai,
        apiKey,
        restPrompt,
        trainerAvatarUrl,
        8
      )

      if (restVideo) {
        const restPath = `${trainerId}/${workoutId}/${safeName}_rest.mp4`
        const restUrl = await uploadVideo('trainer-videos', restPath, restVideo.buffer)

        generatedVideos.push({
          exerciseName,
          videoType: 'rest',
          videoUrl: restUrl,
          videoPath: restPath,
          durationSeconds: 8,
        })

        console.log(`Rest video uploaded: ${restUrl}`)
      } else {
        console.error(`Failed to generate rest video for: ${exerciseName}`)
      }
    }

    if (generatedVideos.length === 0) {
      return NextResponse.json(
        { error: 'No videos were generated' },
        { status: 500 }
      )
    }

    // Save all videos to exercise_videos table
    for (const video of generatedVideos) {
      await (supabase.from('exercise_videos') as any)
        .insert({
          workout_id: workoutId,
          trainer_id: trainerId,
          exercise_name: video.exerciseName,
          video_url: video.videoUrl,
          video_path: video.videoPath,
          video_type: video.videoType,
          duration_seconds: video.durationSeconds,
        })
    }

    // Update workout with primary video_url (first exercise video)
    const primaryVideo = generatedVideos.find(v => v.videoType === 'exercise')
    if (primaryVideo) {
      await (supabase.from('workouts') as any)
        .update({ video_url: primaryVideo.videoUrl })
        .eq('id', workoutId)
    }

    // Mark workout as generated in program_workouts if applicable
    await (supabase.from('program_workouts') as any)
      .update({ video_generated: true })
      .eq('workout_id', workoutId)

    return NextResponse.json({
      workoutId,
      videos: generatedVideos,
      totalVideos: generatedVideos.length,
    })
  } catch (error) {
    console.error('Video generation failed:', error)
    return NextResponse.json(
      { error: error instanceof Error ? error.message : 'Generation failed' },
      { status: 500 }
    )
  }
}
