// api/generate-song.ts
//
// Simple API endpoint for iPhone Shortcuts:
// 1. Accepts a text prompt via POST JSON
// 2. Calls Suno API to generate a song
// 3. Polls for completion
// 4. Returns audio URL and song URL

import { V2GenerateRequest, V2GenerateResponse } from '../src/schemas/requests';

export const config = { runtime: 'edge' };

const SUNO_HOST = (process.env.SUNO_BASE_URL ?? '').replace(/\/+$/, '');
const SUNO_KEY = process.env.SUNO_API_KEY;
const SUNO_SONG_URL_BASE = process.env.SUNO_SONG_URL_BASE || 'https://suno.com/song';
const POLL_MAX_ATTEMPTS = parseInt(process.env.POLL_MAX_ATTEMPTS || '60', 10);
const POLL_INTERVAL_MS = parseInt(process.env.POLL_INTERVAL_MS || '5000', 10);

if (!SUNO_HOST || !SUNO_KEY) {
  throw new Error('SUNO_BASE_URL or SUNO_API_KEY is not set');
}

// Helper to call Suno API directly (server-side)
async function callSunoAPI(endpoint: string, method: string = 'GET', body?: any) {
  const url = `${SUNO_HOST}${endpoint}`;
  const headers: HeadersInit = {
    'Authorization': `Bearer ${SUNO_KEY}`,
    'Content-Type': 'application/json',
  };

  const bodyString = body ? JSON.stringify(body) : undefined;
  if (bodyString && endpoint.includes('/share/link')) {
    console.log(`📤 Sending to ${endpoint}:`, bodyString);
  }

  const response = await fetch(url, {
    method,
    headers,
    body: bodyString,
  });

  if (!response.ok) {
    const errorText = await response.text();
    throw new Error(`Suno API error ${response.status}: ${errorText}`);
  }

  return await response.json();
}

// Generate song using Suno API (server-side version)
async function generateSongServer(prompt: string) {
  // Use gpt_description_prompt for auto-generated lyrics based on the prompt
  // This ensures the prompt is used as a description to generate lyrics, not as literal lyrics
  // prompt field would be for specific lyrics, gpt_description_prompt is for "make me a song about X"
  const generateRequest = V2GenerateRequest.parse({
    gpt_description_prompt: prompt, // Use this for auto lyrics generation
    prompt: '', // Empty - let Suno generate lyrics based on gpt_description_prompt
    tags: null, // Will use defaults - can be enhanced later with style tags
  });

  console.log('📝 Generate request:', JSON.stringify({
    gpt_description_prompt: generateRequest.gpt_description_prompt,
    prompt: generateRequest.prompt,
    override_fields: generateRequest.override_fields,
  }, null, 2));

  const response = await callSunoAPI('/api/generate/v2-web', 'POST', generateRequest);
  return response as V2GenerateResponse;
}

// Create share link for a clip (server-side version)
async function createShareLink(clipId: string): Promise<string | null> {
  try {
    console.log(`🔗 Creating share link for clip: ${clipId}`);
    
    // Make the request directly with explicit headers
    const url = `${SUNO_HOST}/api/share/link`;
    
    // Try different request body formats - the API might expect a different structure
    // Format 1: Nested spec (original)
    const requestBody1 = {
      spec: {
        content_type: 'clip',
        content_id: clipId,
      },
    };
    
    // Format 2: Top-level fields
    const requestBody2 = {
      content_type: 'clip',
      content_id: clipId,
    };
    
    // Format 3: With spec wrapper but different structure
    const requestBody3 = {
      spec: {
        content_type: 'song',
        content_id: clipId,
        platform: 'web',
        source: 'api',
      },
    };
    
    // Try format 1 first (the expected format)
    let requestBody: any = requestBody1;
    console.log('📤 Share link URL:', url);
    console.log('📤 Share link request body (format 1):', JSON.stringify(requestBody, null, 2));
    
    let response = await fetch(url, {
      method: 'POST',
      headers: {
        'Authorization': `Bearer ${SUNO_KEY}`,
        'Content-Type': 'application/json',
        'Accept': 'application/json',
      },
      body: JSON.stringify(requestBody),
    });
    
    // If format 1 fails, try format 2
    if (!response.ok) {
      const errorText1 = await response.text();
      console.log('⚠️ Format 1 failed:', errorText1);
      console.log('⚠️ Trying format 2 (top-level fields)');
      requestBody = requestBody2;
      console.log('📤 Share link request body (format 2):', JSON.stringify(requestBody, null, 2));
      
      response = await fetch(url, {
        method: 'POST',
        headers: {
          'Authorization': `Bearer ${SUNO_KEY}`,
          'Content-Type': 'application/json',
          'Accept': 'application/json',
        },
        body: JSON.stringify(requestBody),
      });
    }
    
    // If format 2 also fails, try format 3
    if (!response.ok) {
      const errorText2 = await response.text();
      console.log('⚠️ Format 2 failed:', errorText2);
      console.log('⚠️ Trying format 3 (with platform/source)');
      requestBody = requestBody3;
      console.log('📤 Share link request body (format 3):', JSON.stringify(requestBody, null, 2));
      
      response = await fetch(url, {
        method: 'POST',
        headers: {
          'Authorization': `Bearer ${SUNO_KEY}`,
          'Content-Type': 'application/json',
          'Accept': 'application/json',
        },
        body: JSON.stringify(requestBody),
      });
    }
    
    console.log('📥 Share link response status:', response.status);
    
    if (!response.ok) {
      const errorText = await response.text();
      console.error('❌ Share link API error:', errorText);
      throw new Error(`Suno API error ${response.status}: ${errorText}`);
    }
    
    const responseData = await response.json();
    console.log('📥 Share link response:', JSON.stringify(responseData, null, 2));
    
    // The API should return a share_id (16-char alphanumeric) which is different from clip_id
    // Response format might be: {success: true, share_id: "LRzIJfAwmSwD6JOT"} or {id: "..."} or {code: "..."}
    const shareId = responseData.share_id || responseData.id || responseData.code;
    
    if (shareId) {
      // Construct the share URL using the share_id (not clip_id)
      const shareUrl = `https://suno.com/s/${shareId}`;
      console.log(`✅ Share link created: ${shareUrl} (share_id: ${shareId})`);
      return shareUrl;
    }
    
    // If response has a link field, try to extract share_id from it
    // But note: link might be the clip URL, not the share URL
    const link = responseData.link || responseData.share_url;
    if (link) {
      // Try to extract share_id from URL pattern /s/{share_id}
      const shareIdMatch = link.match(/\/s\/([^\/]+)/);
      if (shareIdMatch && shareIdMatch[1]) {
        const extractedShareId = shareIdMatch[1];
        const shareUrl = `https://suno.com/s/${extractedShareId}`;
        console.log(`✅ Share link extracted from URL: ${shareUrl} (share_id: ${extractedShareId})`);
        return shareUrl;
      }
      console.log('⚠️ Link field found but does not contain /s/ pattern:', link);
    }
    
    console.log('⚠️ Share link response did not contain share_id:', JSON.stringify(responseData));
    return null;
  } catch (error) {
    console.error('❌ Error creating share link:', error);
    // Don't throw - share link is optional, continue without it
    return null;
  }
}

// Poll for completion (server-side version)
async function pollForCompletionServer(clipIds: string[], maxAttempts: number = POLL_MAX_ATTEMPTS, intervalMs: number = POLL_INTERVAL_MS) {
  for (let attempt = 0; attempt < maxAttempts; attempt++) {
    await new Promise(resolve => setTimeout(resolve, intervalMs));

    const idsParam = clipIds.join(',');
    const response = await callSunoAPI(`/api/feed/v2?ids=${idsParam}`, 'GET');

    if (response.clips && response.clips.length > 0) {
      const clips = response.clips;
      const allComplete = clips.every((clip: any) => 
        clip.status === 'complete' || clip.status === 'error'
      );

      if (allComplete) {
        return clips;
      }
    }
  }

  throw new Error('Song generation timed out');
}

export default async function handler(req: Request): Promise<Response> {
  console.log('📥 Received request to /api/generate-song');
  console.log('   Method:', req.method);
  console.log('   URL:', req.url);
  
  try {
    // Only accept POST requests
    if (req.method !== 'POST') {
      console.log('❌ Method not allowed:', req.method);
      return new Response(
        JSON.stringify({ 
          error: 'Method Not Allowed', 
          message: 'This endpoint only accepts POST requests' 
        }),
        { 
          status: 405,
          headers: { 'Content-Type': 'application/json' }
        }
      );
    }

    // Parse JSON body
    const body = await req.json();
    console.log('📝 Request body:', JSON.stringify(body, null, 2));
    const prompt = body.prompt || body.text || body.message;
    console.log('🎯 Extracted prompt:', prompt);

    if (!prompt || typeof prompt !== 'string') {
      return new Response(
        JSON.stringify({ 
          error: 'Bad Request', 
          message: 'Missing or invalid "prompt" field in request body' 
        }),
        { 
          status: 400,
          headers: { 'Content-Type': 'application/json' }
        }
      );
    }

    console.log(`🎵 Generating song with prompt: ${prompt}`);

    // Generate song using server-side function
    console.log('📝 Calling Suno API...');
    const generateResponse = await generateSongServer(prompt);
    console.log('✅ Song generation started');
    
    if (!generateResponse.clips || generateResponse.clips.length === 0) {
      throw new Error('No clips returned from Suno API');
    }

    const clipIds = generateResponse.clips.map((clip) => clip.id);
    console.log('📋 Generated clips:', clipIds);

    // Wait 3 seconds to give Suno API time to start processing
    console.log('⏳ Waiting 3 seconds for Suno to start processing...');
    await new Promise(resolve => setTimeout(resolve, 3000));
    console.log('✅ Resuming after 3 second delay');

    // Return early with song URL (skip polling for now)
    const firstClipId = clipIds[0];
    const earlySongUrl = `${SUNO_SONG_URL_BASE}/${firstClipId}`;

    console.log('✅ Returning early with song URL:', earlySongUrl);
    console.log('⏭️ Skipping polling (code preserved below)');

    return new Response(
      JSON.stringify({
        success: true,
        audioUrl: null, // Not available yet without polling
        songUrl: earlySongUrl,
        shareUrl: null, // Not available yet without polling
        shareId: null,
        title: 'Generating...',
        clipId: firstClipId,
        message: 'Song generation started. Polling skipped.',
      }),
      {
        status: 200,
        headers: { 
          'Content-Type': 'application/json',
          'Access-Control-Allow-Origin': '*',
          'Access-Control-Allow-Methods': 'POST, OPTIONS',
          'Access-Control-Allow-Headers': 'Content-Type',
        },
      }
    );

    // ===== POLLING CODE PRESERVED BELOW (currently skipped) =====
    // Poll for completion
    console.log('⏳ Polling for completion...');
    const completedClips = await pollForCompletionServer(clipIds);

    // Get the first completed clip
    const completedClip = completedClips.find((clip: any) => clip.status === 'complete');
    
    if (!completedClip) {
      const errorClip = completedClips.find((clip: any) => clip.status === 'error');
      const errorMsg = errorClip?.metadata?.error_message || 'Unknown error';
      throw new Error(`Song generation failed: ${errorMsg}`);
    }

    // Get audio URL and song page URL
    const audioUrl = completedClip.audio_url;
    const songUrl = `${SUNO_SONG_URL_BASE}/${completedClip.id}`;
    
    // Create share link after completion
    // Note: clip_id is used to CREATE the share_id, but share_id is a different value
    console.log('🔗 Creating share link for completed clip:', completedClip.id);
    const shareUrlResult = await createShareLink(completedClip.id);
    
    // Extract share_id from the share URL (format: https://suno.com/s/{share_id})
    let shareId: string | null = null;
    let shareUrl: string | null = shareUrlResult;
    if (shareUrlResult !== null) {
      const nonNullShareUrl = shareUrlResult as string;
      shareUrl = nonNullShareUrl;
      const shareIdMatch = nonNullShareUrl.match(/\/s\/([^\/]+)/);
      const extractedShareId = shareIdMatch?.[1];
      if (extractedShareId) {
        shareId = extractedShareId || null;
        console.log(`📋 Extracted share_id: ${shareId} (from clip_id: ${completedClip.id})`);
      } else {
        console.log('⚠️ Could not extract share_id from shareUrl:', nonNullShareUrl);
      }
    }

    if (!audioUrl) {
      throw new Error('No audio URL in completed clip');
    }

    console.log('✅ Song completed!');
    console.log('   Audio URL:', audioUrl);
    console.log('   Song URL:', songUrl);
    if (shareUrl) {
      console.log('   Share URL:', shareUrl);
    }

    const responseData = {
      success: true,
      audioUrl: audioUrl,
      songUrl: songUrl,
      shareUrl: shareUrl,
      shareId: shareId,
      title: completedClip.title || 'Generated Song',
      clipId: completedClip.id,
    };
    
    console.log('📤 Sending response:', JSON.stringify(responseData, null, 2));

    // Return JSON response with audio URL and song URL
    return new Response(
      JSON.stringify(responseData),
      {
        status: 200,
        headers: { 
          'Content-Type': 'application/json',
          'Access-Control-Allow-Origin': '*',
          'Access-Control-Allow-Methods': 'POST, OPTIONS',
          'Access-Control-Allow-Headers': 'Content-Type',
        },
      }
    );

  } catch (error) {
    console.error('❌ Error generating song:', error);
    if (error instanceof Error) {
      console.error('   Error message:', error.message);
      console.error('   Error stack:', error.stack);
    }
    
    const errorMessage = error instanceof Error ? error.message : 'Unknown error';
    const errorResponse = {
      success: false,
      error: errorMessage,
    };
    
    console.log('📤 Sending error response:', JSON.stringify(errorResponse, null, 2));
    
    return new Response(
      JSON.stringify(errorResponse),
      {
        status: 500,
        headers: { 
          'Content-Type': 'application/json',
          'Access-Control-Allow-Origin': '*',
        },
      }
    );
  }
}

