import { readdir, readFile, mkdir, writeFile } from 'fs/promises';
import { join, dirname, basename } from 'path';
import { fileURLToPath } from 'url';
import { existsSync } from 'fs';

const __filename = fileURLToPath(import.meta.url);
const __dirname = dirname(__filename);

// Website CI/Style Guide
const CI_STYLE = {
  colors: {
    primary: 'sage green (#697565)',
    background: 'dark moss (#181C14)',
    accent: 'dark sage (#465B50)',
    text: 'cream/off-white (#ECDFCC)'
  },
  style: 'minimalist, glass-morphism, organic, professional, modern',
  aesthetic: 'dark background with sage green and cream accents, subtle gradients, clean lines'
};

// Directories
const BLOG_POSTS_DIR = join(__dirname, '../blog-posts');
const OUTPUT_DIR = join(__dirname, '../source-images/posts');

/**
 * Call Google Gemini / Nano Banana Pro Image Generation API
 */
async function callGeminiImageAPI(prompt, apiKey) {
  const model = 'gemini-2.0-flash-exp'; // Nano Banana model
  const url = `https://generativelanguage.googleapis.com/v1beta/models/${model}:generateContent?key=${apiKey}`;

  const response = await fetch(url, {
    method: 'POST',
    headers: {
      'Content-Type': 'application/json'
    },
    body: JSON.stringify({
      contents: [{
        parts: [{ text: prompt }]
      }],
      generationConfig: {
        responseModalities: ['TEXT', 'IMAGE']
      }
    })
  });

  if (!response.ok) {
    const error = await response.json().catch(() => ({}));
    const errorMessage = error.error?.message || response.statusText;
    throw new Error(`Gemini API Error: ${response.status} - ${errorMessage}`);
  }

  return response.json();
}

/**
 * Call OpenAI Image Generation API directly using fetch
 */
async function callOpenAIImageAPI(prompt, apiKey) {
  const response = await fetch('https://api.openai.com/v1/images/generations', {
    method: 'POST',
    headers: {
      'Authorization': `Bearer ${apiKey}`,
      'Content-Type': 'application/json'
    },
    body: JSON.stringify({
      model: 'gpt-image-1.5',
      prompt: prompt,
      n: 1,
      size: '1536x1024', // 3:2 landscape (closest to 16:9 for gpt-image-1.5)
      quality: 'high'
    })
  });

  if (!response.ok) {
    const error = await response.json().catch(() => ({}));
    throw new Error(`OpenAI API Error: ${response.status} - ${error.error?.message || response.statusText}`);
  }

  return response.json();
}

/**
 * Extract image prompts from a blog post markdown file
 */
function extractImagePrompts(content, filename) {
  const prompts = [];

  // Find the "Bildprompts" section
  const bildpromptsMatch = content.match(/## Bildprompts[\s\S]*?(?=##|---|\n\n\n|$)/i);

  if (bildpromptsMatch) {
    const section = bildpromptsMatch[0];

    // Extract prompts in quotes
    const promptMatches = section.matchAll(/"([^"]+)"/g);

    for (const match of promptMatches) {
      prompts.push(match[1]);
    }
  }

  // Fallback: look for image prompt patterns
  if (prompts.length === 0) {
    const fallbackMatches = content.matchAll(/\*\*Bild \d+[^*]*\*\*[:\s]*"?([^"\n]+)"?/gi);
    for (const match of fallbackMatches) {
      prompts.push(match[1]);
    }
  }

  return prompts;
}

/**
 * Adapt a prompt to match the website's CI
 */
function adaptPromptToCI(originalPrompt, isHeroImage = false) {
  // Extract the core concept from the original prompt
  let concept = originalPrompt
    .replace(/dark blue and cyan/gi, '')
    .replace(/blue accents/gi, '')
    .replace(/white background/gi, '')
    .replace(/bright colors/gi, '')
    .replace(/neon/gi, '')
    .replace(/vibrant/gi, '')
    .replace(/cyan/gi, '')
    .replace(/8k ultra-realistic/gi, '')
    .replace(/cinematic lighting/gi, '')
    .replace(/color scheme/gi, '')
    .trim();

  // Build CI-compliant prompt - REALISTIC style with CI colors
  const ciPrompt = `
Photorealistic, cinematic image for a professional tech blog. 16:9 wide format, 4K quality.

COLOR GRADING (apply as color filter/mood):
- Overall mood: Dark, moody atmosphere with deep shadows
- Dominant tones: Dark greenish-black (#181C14), muted sage green (#697565)
- Accent lighting: Warm cream/off-white (#ECDFCC) highlights
- Color temperature: Slightly warm, earthy undertones
- NO bright blue, NO cyan, NO neon colors

PHOTOGRAPHY STYLE:
- Ultra-realistic, photographic quality
- Cinematic wide-angle composition
- Professional lighting with dramatic shadows
- Shallow depth of field where appropriate
- High-end commercial photography look
- Shot on Sony A7R IV, 24-70mm f/2.8 lens

SCENE: ${concept}

Create a realistic, professional photograph. The lighting should create a moody, sophisticated atmosphere using the sage green and cream color palette as accent lighting or environmental color.

NO text overlays, NO watermarks, NO logos.
`.trim();

  return ciPrompt;
}

/**
 * Generate an image using OpenAI's gpt-image-1.5
 */
async function generateImage(prompt, outputPath, apiKey, provider = 'gemini', retries = 3) {
  for (let attempt = 1; attempt <= retries; attempt++) {
    try {
      console.log(`  Generating image (attempt ${attempt}/${retries}) via ${provider}...`);
      console.log(`  Prompt: ${prompt.substring(0, 100)}...`);

      let imageBuffer;

      if (provider === 'gemini') {
        // Use Google Gemini / Nano Banana Pro
        const response = await callGeminiImageAPI(prompt, apiKey);

        // Extract image from Gemini response
        const candidate = response.candidates?.[0];
        if (!candidate) {
          throw new Error('No candidates in response');
        }

        const parts = candidate.content?.parts || [];
        const imagePart = parts.find(p => p.inlineData);

        if (!imagePart?.inlineData?.data) {
          // Check if there's text response (might be safety block)
          const textPart = parts.find(p => p.text);
          if (textPart) {
            console.log(`  Response text: ${textPart.text.substring(0, 100)}...`);
          }
          throw new Error('No image data in Gemini response');
        }

        imageBuffer = Buffer.from(imagePart.inlineData.data, 'base64');

      } else {
        // Use OpenAI
        const response = await callOpenAIImageAPI(prompt, apiKey);
        const imageResult = response.data[0];

        if (imageResult.b64_json) {
          imageBuffer = Buffer.from(imageResult.b64_json, 'base64');
        } else if (imageResult.url) {
          console.log(`  Downloading from URL...`);
          const imageResponse = await fetch(imageResult.url);
          if (!imageResponse.ok) {
            throw new Error(`Failed to download image: ${imageResponse.status}`);
          }
          const arrayBuffer = await imageResponse.arrayBuffer();
          imageBuffer = Buffer.from(arrayBuffer);
        } else {
          throw new Error('No image data in response');
        }
      }

      // Save the image
      await writeFile(outputPath, imageBuffer);
      console.log(`  ✓ Saved: ${outputPath}`);

      return true;
    } catch (error) {
      console.error(`  ✗ Attempt ${attempt} failed:`, error.message);

      if (attempt === retries) {
        throw error;
      }

      // Wait before retry
      await new Promise(resolve => setTimeout(resolve, 2000 * attempt));
    }
  }
}

/**
 * Process a single blog post
 */
async function processBlogPost(filename, apiKey, options = {}) {
  const { dryRun = false, forceRegenerate = false, onlyHero = true, provider = 'gemini' } = options;

  const filePath = join(BLOG_POSTS_DIR, filename);
  const content = await readFile(filePath, 'utf-8');

  // Extract slug from filename (e.g., "01-agentic-ai-2026.md" -> "01-agentic-ai-2026")
  const slug = basename(filename, '.md');

  // Extract image prompts
  const prompts = extractImagePrompts(content, filename);

  if (prompts.length === 0) {
    console.log(`⚠ No image prompts found in ${filename}`);
    return { filename, slug, generated: 0, skipped: 0 };
  }

  console.log(`\n📄 ${filename}`);
  console.log(`   Found ${prompts.length} image prompt(s)`);

  // Create output directory
  const postOutputDir = join(OUTPUT_DIR, slug);
  if (!dryRun) {
    await mkdir(postOutputDir, { recursive: true });
  }

  let generated = 0;
  let skipped = 0;

  // Process prompts (only hero image by default)
  const promptsToProcess = onlyHero ? [prompts[0]] : prompts;

  for (let i = 0; i < promptsToProcess.length; i++) {
    const prompt = promptsToProcess[i];
    const imageName = i === 0 ? 'cover.jpg' : `image-${i + 1}.jpg`;
    const outputPath = join(postOutputDir, imageName);

    // Check if image already exists
    if (existsSync(outputPath) && !forceRegenerate) {
      console.log(`   ⏭ Skipping ${imageName} (already exists)`);
      skipped++;
      continue;
    }

    // Adapt prompt to CI
    const adaptedPrompt = adaptPromptToCI(prompt, i === 0);

    if (dryRun) {
      console.log(`   [DRY RUN] Would generate: ${imageName}`);
      console.log(`   Original: ${prompt.substring(0, 80)}...`);
      console.log(`   Adapted: ${adaptedPrompt.substring(0, 80)}...`);
    } else {
      try {
        await generateImage(adaptedPrompt, outputPath, apiKey, provider);
        generated++;

        // Rate limiting: wait between requests
        if (i < promptsToProcess.length - 1) {
          console.log('   Waiting 2s before next image...');
          await new Promise(resolve => setTimeout(resolve, 2000));
        }
      } catch (error) {
        console.error(`   ✗ Failed to generate ${imageName}:`, error.message);
      }
    }
  }

  return { filename, slug, generated, skipped };
}

/**
 * Main function
 */
async function main() {
  console.log('🎨 Blog Image Generator');
  console.log('========================\n');

  // Get API key from environment or command line
  const apiKey = process.env.OPENAI_API_KEY ||
    process.argv.find(a => a.startsWith('--api-key='))?.split('=')[1];

  // Check for API key
  if (!apiKey) {
    console.error('❌ Error: OPENAI_API_KEY not provided');
    console.log('\nUsage:');
    console.log('  export OPENAI_API_KEY=sk-your-key-here');
    console.log('  node scripts/generate-blog-images.js');
    console.log('\nOr:');
    console.log('  node scripts/generate-blog-images.js --api-key=sk-your-key-here');
    process.exit(1);
  }

  // Detect provider based on API key format
  const provider = apiKey.startsWith('AIzaSy') ? 'gemini' : 'openai';
  console.log(`Provider: ${provider === 'gemini' ? 'Google Gemini (Nano Banana)' : 'OpenAI'}\n`);

  // Parse command line arguments
  const args = process.argv.slice(2);
  const options = {
    dryRun: args.includes('--dry-run'),
    forceRegenerate: args.includes('--force'),
    onlyHero: !args.includes('--all-images'),
    single: args.find(a => a.startsWith('--file='))?.split('=')[1],
    range: args.find(a => a.startsWith('--range='))?.split('=')[1],
    provider
  };

  if (options.dryRun) {
    console.log('🔍 DRY RUN MODE - No images will be generated\n');
  }

  console.log(`CI Style: ${CI_STYLE.style}`);
  console.log(`Colors: ${Object.values(CI_STYLE.colors).join(', ')}\n`);

  // Get list of blog posts
  let files;

  if (options.single) {
    files = [options.single];
  } else {
    files = (await readdir(BLOG_POSTS_DIR))
      .filter(f => f.endsWith('.md'))
      .sort();

    // Filter by range if specified (e.g., --range=1-10)
    if (options.range) {
      const [start, end] = options.range.split('-').map(Number);
      files = files.filter(f => {
        const num = parseInt(f.split('-')[0], 10);
        return num >= start && num <= end;
      });
    }
  }

  console.log(`Found ${files.length} blog post(s) to process\n`);

  // Process each blog post
  const results = [];

  for (const file of files) {
    try {
      const result = await processBlogPost(file, apiKey, options);
      results.push(result);
    } catch (error) {
      console.error(`❌ Error processing ${file}:`, error.message);
      results.push({ filename: file, error: error.message });
    }
  }

  // Summary
  console.log('\n========================');
  console.log('📊 Summary\n');

  const totalGenerated = results.reduce((sum, r) => sum + (r.generated || 0), 0);
  const totalSkipped = results.reduce((sum, r) => sum + (r.skipped || 0), 0);
  const totalErrors = results.filter(r => r.error).length;

  console.log(`✓ Generated: ${totalGenerated} images`);
  console.log(`⏭ Skipped: ${totalSkipped} images (already exist)`);
  console.log(`✗ Errors: ${totalErrors}`);

  if (!options.dryRun && totalGenerated > 0) {
    console.log('\n📝 Next steps:');
    console.log('1. Review generated images in source-images/posts/');
    console.log('2. Run `npm run build:images` to optimize images');
  }
}

// Run
main().catch(console.error);
