/**
 * fal.ai Service - Image Generation
 * 
 * Handles image generation for character references and comic panels
 * Uses NanoBanan model for anime/manga-style artwork
 */

import { fal } from '@fal-ai/client';
import type { Character, Panel, PanelImage } from '@/types';
import { 
  buildCharacterPrompt,
  generatePanelSeed 
} from '@/utils/characterTemplates';

const FAL_KEY = import.meta.env.VITE_FAL_KEY;

if (!FAL_KEY) {
  console.warn('VITE_FAL_KEY not set. Image generation will not work.');
}

fal.config({
  credentials: FAL_KEY || 'dummy-key',
});

// Art style keywords mapping
const ART_STYLE_KEYWORDS: Record<string, string> = {
  'manga': 'Japanese manga style, black and white ink, screentone shading, speed lines, dramatic shadows, clean linework, right-to-left reading',
  'western-comic': 'American comic book style, bold outlines, vibrant colors, dynamic poses, cross-hatching, Ben-Day dots, left-to-right reading',
  'pixel-art': '16-bit pixel art style, retro game aesthetic, limited color palette, crisp pixels, dithering, nostalgic',
  'watercolor': 'watercolor painting style, soft edges, paper texture, translucent washes, delicate linework, artistic',
  'noir': 'film noir style, high contrast black and white, dramatic chiaroscuro lighting, gritty, shadow-heavy, 1940s aesthetic',
  'chibi': 'chibi anime style, super deformed characters, big heads, small bodies, cute, colorful, expressive',
  'sketch': 'pencil sketch style, rough linework, cross-hatching, construction lines, draft aesthetic, monochrome',
  'cyberpunk': 'cyberpunk aesthetic, neon lighting, futuristic cityscapes, holographic elements, high contrast, synthwave colors',
};

// Default style modifier for quality
const QUALITY_MODIFIER = 'high quality, detailed, clean lines, vibrant colors, professional illustration, best quality, masterpiece';

/**
 * Map shot type to optimal image dimensions
 */
function getImageSizeForShotType(shotType: string): "square" | "landscape_16_9" | "landscape_4_3" | "portrait_4_3" | "square_hd" | "portrait_16_9" {
  const mapping: Record<string, "square" | "landscape_16_9" | "landscape_4_3" | "portrait_4_3" | "square_hd" | "portrait_16_9"> = {
    'establishing': 'landscape_16_9',
    'wide': 'landscape_16_9',
    'medium': 'landscape_4_3',
    'close-up': 'portrait_4_3',
    'extreme-close-up': 'square_hd',
    'over-shoulder': 'landscape_4_3',
    'aerial': 'landscape_16_9',
  };
  return mapping[shotType] || 'landscape_4_3';
}

/**
 * Generate character reference portrait
 * This is the master anchor image for consistency
 */
export async function generateCharacterReference(
  character: Character,
  artStyle: string
): Promise<string> {
  if (!FAL_KEY) {
    throw new Error('fal.ai API key not configured. Please set VITE_FAL_KEY in .env.local');
  }

  const styleKeywords = ART_STYLE_KEYWORDS[artStyle] || artStyle;
  const prompt = buildCharacterPrompt(
    character.promptTemplate,
    'standing in neutral pose facing camera, character portrait, clean background',
    'studio lighting, white background',
    'front-facing portrait, centered composition',
    `${styleKeywords}, ${QUALITY_MODIFIER}`
  );

  try {
    const result = await fal.subscribe('fal-ai/fast-sdxl', {
      input: {
        prompt,
        negative_prompt: 'blurry, low quality, distorted face, extra limbs, bad anatomy, deformed, watermark, signature',
        seed: character.seed,
        image_size: 'square_hd',
        num_inference_steps: 30,
        guidance_scale: 7.5,
      },
    });

    if (!result.data?.images?.[0]?.url) {
      throw new Error('No image returned from fal.ai');
    }

    return result.data.images[0].url;
  } catch (error) {
    console.error('Character reference generation failed:', error);
    throw new Error(`Failed to generate character reference: ${error instanceof Error ? error.message : 'Unknown error'}`);
  }
}

/**
 * Generate multi-angle character sheet (Professional mode)
 * Creates front, 3/4, profile, and back views
 */
export async function generateCharacterSheet(
  character: Character,
  artStyle: string
): Promise<string[]> {
  if (!FAL_KEY) {
    throw new Error('fal.ai API key not configured');
  }

  const styleKeywords = ART_STYLE_KEYWORDS[artStyle] || artStyle;
  const poses = [
    { name: 'front-facing portrait', view: 'front' },
    { name: 'three-quarter view portrait', view: 'three-quarter' },
    { name: 'side profile view', view: 'profile' },
    { name: 'back view showing hair and outfit', view: 'back' },
  ];

  const sheetUrls: string[] = [];

  for (let i = 0; i < poses.length; i++) {
    const pose = poses[i];
    
    const prompt = buildCharacterPrompt(
      character.promptTemplate,
      `${pose.name}, ${pose.view} view, character reference, clean background`,
      'studio lighting, white background',
      `${pose.view} view, centered composition`,
      `${styleKeywords}, ${QUALITY_MODIFIER}`
    );

    // Use previous image as reference for consistency
    const referenceImages = sheetUrls.length > 0 ? [sheetUrls[0]] : undefined;

    try {
      const result = await fal.subscribe('fal-ai/fast-sdxl', {
        input: {
          prompt,
          negative_prompt: 'blurry, low quality, distorted face, extra limbs, bad anatomy, deformed',
          seed: character.seed + i, // Increment seed for variation
          image_size: 'square_hd',
          num_inference_steps: 30,
          guidance_scale: 7.5,
          ...(referenceImages && {
            reference_images: referenceImages,
            reference_image_strength: 0.65, // Sweet spot for preserving identity
          }),
        },
      });

      if (result.data?.images?.[0]?.url) {
        sheetUrls.push(result.data.images[0].url);
      }
    } catch (error) {
      console.error(`Failed to generate ${pose.view} view:`, error);
      // Continue with other poses even if one fails
    }
  }

  if (sheetUrls.length === 0) {
    throw new Error('Failed to generate any character sheet images');
  }

  return sheetUrls;
}

/**
 * Generate panel image with character consistency
 * Uses character reference images for IP-Adapter consistency
 */
export async function generatePanelImage(
  panel: Panel,
  characters: Character[],
  artStyle: string,
  projectId: string
): Promise<PanelImage> {
  if (!FAL_KEY) {
    throw new Error('fal.ai API key not configured');
  }

  const styleKeywords = ART_STYLE_KEYWORDS[artStyle] || artStyle;
  
  // Build character prompts for all characters in the panel
  const characterPrompts = panel.charactersPresent.map(charId => {
    const char = characters.find(c => c.id === charId);
    if (!char) return '';
    return buildCharacterPrompt(
      char.promptTemplate,
      panel.description,
      '', // setting is in panel.description
      '', // lighting is in panel.description  
      styleKeywords
    );
  }).filter(Boolean).join('. ');

  const fullPrompt = `${styleKeywords} comic panel. ${panel.description}. Characters: ${characterPrompts}. ${panel.shotType} shot. ${QUALITY_MODIFIER}`;

  // Collect reference images for all characters
  const referenceImages = panel.charactersPresent
    .map(id => characters.find(c => c.id === id)?.referenceImageUrl)
    .filter((url): url is string => Boolean(url));

  // Generate deterministic seed for this panel
  const seed = generatePanelSeed(
    projectId,
    1, // We don't have page number in Panel, use 1
    panel.panelNumber,
    panel.panelId
  );

  try {
    const result = await fal.subscribe('fal-ai/fast-sdxl', {
      input: {
        prompt: fullPrompt,
        negative_prompt: 'blurry, low quality, distorted face, extra limbs, bad anatomy, deformed, watermark, signature, text, speech bubble',
        seed,
        image_size: getImageSizeForShotType(panel.shotType),
        num_inference_steps: 30,
        guidance_scale: 7.5,
        ...(referenceImages.length > 0 && {
          reference_images: referenceImages,
          reference_image_strength: 0.65,
        }),
      },
    });

    if (!result.data?.images?.[0]) {
      throw new Error('No image returned from fal.ai');
    }

    const image = result.data.images[0];

    return {
      url: image.url,
      width: image.width || 1024,
      height: image.height || 1024,
      seed,
      prompt: fullPrompt,
    };
  } catch (error) {
    console.error('Panel generation failed:', error);
    throw new Error(`Failed to generate panel: ${error instanceof Error ? error.message : 'Unknown error'}`);
  }
}

/**
 * Generate all panels in parallel batches
 * Prevents overwhelming the API while maintaining efficiency
 */
export async function generateAllPanels(
  panels: Panel[],
  characters: Character[],
  artStyle: string,
  projectId: string,
  onProgress?: (progress: number) => void
): Promise<Record<string, PanelImage>> {
  const batchSize = 3; // Max concurrent requests
  const results: Record<string, PanelImage> = {};

  for (let i = 0; i < panels.length; i += batchSize) {
    const batch = panels.slice(i, i + batchSize);
    
    const batchResults = await Promise.allSettled(
      batch.map(panel => generatePanelImage(panel, characters, artStyle, projectId))
    );

    batchResults.forEach((result, idx) => {
      const panel = batch[idx];
      if (result.status === 'fulfilled') {
        results[panel.panelId] = result.value;
      } else {
        console.error(`Failed to generate panel ${panel.panelId}:`, result.reason);
      }
    });

    // Report progress
    if (onProgress) {
      onProgress(Math.min(((i + batch.length) / panels.length) * 100, 100));
    }

    // Small delay between batches to avoid rate limits
    if (i + batchSize < panels.length) {
      await new Promise(resolve => setTimeout(resolve, 500));
    }
  }

  return results;
}
