<?php
/**
 * SillyBubble Image Generator
 * 
 * This script generates comic-style chat bubble images with characters.
 * It supports character-based styling with speech or thought bubbles.
 * 
 * Usage:
 * image.php?q=Hello+World
 * image.php?q=Hello+World&character=Example
 * image.php?q=Hello+World&character=Example&bubble_type=thought
 * image.php?q=Hello+World&style=Example (legacy style parameter maps to character)
 */

// Set content type to PNG image
header('Content-Type: image/png');

// Get parameters
$text = isset($_GET['q']) ? urldecode($_GET['q']) : 'No text provided';
$character = isset($_GET['character']) ? $_GET['character'] : 'Example';
$bubble_type = isset($_GET['bubble_type']) ? $_GET['bubble_type'] : 'speech';
$style = isset($_GET['style']) ? $_GET['style'] : 'default';

// If style parameter is used but no character is specified, use style as character name
if (!isset($_GET['character']) && isset($_GET['style']) && $style != 'default') {
    $character = $style;
}

// Validate bubble_type - only 'speech' or 'thought' allowed
if ($bubble_type != 'speech' && $bubble_type != 'thought') {
    $bubble_type = 'speech';
}

// Define canvas dimensions (5:1 ratio)
$canvasWidth = 2000;
$canvasHeight = 400;
$charWidth = 400; // 20% of canvas width
$bubbleWidth = 1400; // 70% of canvas width
$bubbleMargin = 100; // 5% margin on each side
$bubblePadding = 50; // Padding inside the bubble

// Define legacy styles for backward compatibility
$styles = [
    'default' => [
        'bg_color' => [245, 245, 245],
        'text_color' => [50, 50, 50],
        'border_color' => [200, 200, 200],
        'font_size' => 24, // Increased for higher resolution
        'line_height' => 30,
        'font' => __DIR__ . '/fonts/NotoSans-Regular.ttf',
    ],
    'modern' => [
        'bg_color' => [66, 133, 244],
        'text_color' => [255, 255, 255],
        'border_color' => [59, 120, 220],
        'font_size' => 24,
        'line_height' => 30,
        'font' => __DIR__ . '/fonts/NotoSans-Regular.ttf',
    ],
    'retro' => [
        'bg_color' => [255, 204, 102],
        'text_color' => [51, 51, 51],
        'border_color' => [204, 153, 0],
        'font_size' => 24,
        'line_height' => 30,
        'font' => __DIR__ . '/fonts/NotoSans-Regular.ttf',
    ],
    'minimal' => [
        'bg_color' => [255, 255, 255],
        'text_color' => [0, 0, 0],
        'border_color' => [220, 220, 220],
        'font_size' => 24,
        'line_height' => 30,
        'font' => __DIR__ . '/fonts/NotoSans-Regular.ttf',
    ],
];

// Set default styling
$config = [
    'bg_color' => [245, 245, 245],
    'text_color' => [50, 50, 50],
    'border_color' => [200, 200, 200],
    'font_size' => 24,
    'line_height' => 30,
    'font' => __DIR__ . '/fonts/NotoSans-Regular.ttf',
];

// Ensure required directories exist
$dirs = [
    __DIR__ . '/characters/Example',
    __DIR__ . '/fonts'
];

foreach ($dirs as $dir) {
    if (!is_dir($dir)) {
        mkdir($dir, 0755, true);
    }
}

// Fallback to a built-in font if the specified font file doesn't exist
if (!file_exists($config['font'])) {
    // Try to find any TTF font in the fonts directory
    $fontFiles = glob(__DIR__ . '/fonts/*.ttf');
    if (!empty($fontFiles)) {
        $config['font'] = $fontFiles[0];
    } else {
        $config['use_builtin_font'] = true;
    }
}

// Create the canvas
$canvas = imagecreatetruecolor($canvasWidth, $canvasHeight);

// Set default white background
$whiteColor = imagecolorallocate($canvas, 255, 255, 255);
imagefill($canvas, 0, 0, $whiteColor);

// Set text color
$textColor = imagecolorallocate($canvas, $config['text_color'][0], $config['text_color'][1], $config['text_color'][2]);

// Function to get image path with fallback to Example
function getAssetPath($assetType, $character) {
    // Primary path in character's directory
    $primaryPath = __DIR__ . '/characters/' . $character . '/' . $assetType . '.png';
    
    // Fallback to Example character
    $fallbackPath = __DIR__ . '/characters/Example/' . $assetType . '.png';
    
    return file_exists($primaryPath) ? $primaryPath : $fallbackPath;
}

// Check for and load the background image
$backgroundPath = getAssetPath('background', $character);
$backgroundLoaded = false;

if (file_exists($backgroundPath)) {
    $backgroundImage = imagecreatefrompng($backgroundPath);
    if ($backgroundImage) {
        // Resize if needed
        $bgWidth = imagesx($backgroundImage);
        $bgHeight = imagesy($backgroundImage);
        
        // Copy background to canvas, resizing if necessary
        imagecopyresampled($canvas, $backgroundImage, 0, 0, 0, 0, $canvasWidth, $canvasHeight, $bgWidth, $bgHeight);
        imagedestroy($backgroundImage);
        $backgroundLoaded = true;
    }
}

// If no background was loaded, use a solid color background
if (!$backgroundLoaded) {
    // Use legacy style background color if it exists
    if (isset($styles[$style])) {
        $bgColor = imagecolorallocate($canvas, 
            $styles[$style]['bg_color'][0], 
            $styles[$style]['bg_color'][1], 
            $styles[$style]['bg_color'][2]
        );
    } else {
        $bgColor = imagecolorallocate($canvas, 245, 245, 245); // Default light gray
    }
    imagefilledrectangle($canvas, 0, 0, $canvasWidth-1, $canvasHeight-1, $bgColor);
}

// Check for and load the character image
$characterPath = getAssetPath('character', $character);
$characterLoaded = false;

if (file_exists($characterPath)) {
    $characterImage = imagecreatefrompng($characterPath);
    if ($characterImage) {
        // Enable alpha blending
        imagesavealpha($characterImage, true);
        
        // Calculate position (center vertically, align left)
        $charWidth = imagesx($characterImage);
        $charHeight = imagesy($characterImage);
        $charX = $bubbleMargin;
        $charY = ($canvasHeight - $charHeight) / 2;
        
        // Copy character to canvas
        imagecopy($canvas, $characterImage, $charX, $charY, 0, 0, $charWidth, $charHeight);
        imagedestroy($characterImage);
        $characterLoaded = true;
    }
}

// Check for and load the bubble image
$bubblePath = getAssetPath($bubble_type, $character);
$bubbleLoaded = false;

if (file_exists($bubblePath)) {
    $bubbleImage = imagecreatefrompng($bubblePath);
    if ($bubbleImage) {
        // Enable alpha blending
        imagesavealpha($bubbleImage, true);
        
        // Calculate position (center vertically, align right of character)
        $bubbleWidth = imagesx($bubbleImage);
        $bubbleHeight = imagesy($bubbleImage);
        $bubbleX = $charWidth + $bubbleMargin * 2;
        $bubbleY = ($canvasHeight - $bubbleHeight) / 2;
        
        // Copy bubble to canvas
        imagecopy($canvas, $bubbleImage, $bubbleX, $bubbleY, 0, 0, $bubbleWidth, $bubbleHeight);
        imagedestroy($bubbleImage);
        $bubbleLoaded = true;
    }
}

// If no bubble was loaded, draw a simple bubble
if (!$bubbleLoaded) {
    // Calculate bubble dimensions and position
    $bubbleX = $charWidth + $bubbleMargin * 2;
    $bubbleY = $canvasHeight * 0.1;
    $bubbleWidth = $canvasWidth - $bubbleX - $bubbleMargin;
    $bubbleHeight = $canvasHeight * 0.8;
    
    // Determine bubble style based on legacy styles if available
    if (isset($styles[$style])) {
        $bubbleBgColor = imagecolorallocate($canvas, 
            $styles[$style]['bg_color'][0], 
            $styles[$style]['bg_color'][1], 
            $styles[$style]['bg_color'][2]
        );
        $bubbleBorderColor = imagecolorallocate($canvas, 
            $styles[$style]['border_color'][0], 
            $styles[$style]['border_color'][1], 
            $styles[$style]['border_color'][2]
        );
    } else {
        $bubbleBgColor = imagecolorallocate($canvas, 245, 245, 245); // Default light gray
        $bubbleBorderColor = imagecolorallocate($canvas, 200, 200, 200); // Default gray border
    }
    
    // Draw bubble based on type
    if ($bubble_type == 'thought') {
        // Draw a thought bubble (rounded rectangle with smaller circles)
        $radius = 40;
        
        // Main bubble
        imagefilledrectangle($canvas, $bubbleX + $radius, $bubbleY, $bubbleX + $bubbleWidth - $radius, $bubbleY + $bubbleHeight, $bubbleBgColor);
        imagefilledrectangle($canvas, $bubbleX, $bubbleY + $radius, $bubbleX + $bubbleWidth, $bubbleY + $bubbleHeight - $radius, $bubbleBgColor);
        
        // Corners
        imagefilledarc($canvas, $bubbleX + $radius, $bubbleY + $radius, $radius * 2, $radius * 2, 180, 270, $bubbleBgColor, IMG_ARC_PIE);
        imagefilledarc($canvas, $bubbleX + $bubbleWidth - $radius, $bubbleY + $radius, $radius * 2, $radius * 2, 270, 360, $bubbleBgColor, IMG_ARC_PIE);
        imagefilledarc($canvas, $bubbleX + $radius, $bubbleY + $bubbleHeight - $radius, $radius * 2, $radius * 2, 90, 180, $bubbleBgColor, IMG_ARC_PIE);
        imagefilledarc($canvas, $bubbleX + $bubbleWidth - $radius, $bubbleY + $bubbleHeight - $radius, $radius * 2, $radius * 2, 0, 90, $bubbleBgColor, IMG_ARC_PIE);
        
        // Draw small circles leading to character
        $circleCount = 3;
        $startX = $bubbleX - 20;
        $startY = $bubbleY + $bubbleHeight/2 + 20;
        
        for ($i = 0; $i < $circleCount; $i++) {
            $circleRadius = 15 - ($i * 4);
            $circleX = $startX - ($i * 30);
            $circleY = $startY + ($i * 20);
            imagefilledellipse($canvas, $circleX, $circleY, $circleRadius*2, $circleRadius*2, $bubbleBgColor);
            imageellipse($canvas, $circleX, $circleY, $circleRadius*2, $circleRadius*2, $bubbleBorderColor);
        }
        
        // Border
        imagerectangle($canvas, $bubbleX + $radius, $bubbleY, $bubbleX + $bubbleWidth - $radius, $bubbleY + $bubbleHeight, $bubbleBorderColor);
        imagerectangle($canvas, $bubbleX, $bubbleY + $radius, $bubbleX + $bubbleWidth, $bubbleY + $bubbleHeight - $radius, $bubbleBorderColor);
        imagearc($canvas, $bubbleX + $radius, $bubbleY + $radius, $radius * 2, $radius * 2, 180, 270, $bubbleBorderColor);
        imagearc($canvas, $bubbleX + $bubbleWidth - $radius, $bubbleY + $radius, $radius * 2, $radius * 2, 270, 360, $bubbleBorderColor);
        imagearc($canvas, $bubbleX + $radius, $bubbleY + $bubbleHeight - $radius, $radius * 2, $radius * 2, 90, 180, $bubbleBorderColor);
        imagearc($canvas, $bubbleX + $bubbleWidth - $radius, $bubbleY + $bubbleHeight - $radius, $radius * 2, $radius * 2, 0, 90, $bubbleBorderColor);
        
    } else {
        // Draw a speech bubble (rounded rectangle with a pointer)
        $radius = 40;
        
        // Main bubble
        imagefilledrectangle($canvas, $bubbleX + $radius, $bubbleY, $bubbleX + $bubbleWidth - $radius, $bubbleY + $bubbleHeight, $bubbleBgColor);
        imagefilledrectangle($canvas, $bubbleX, $bubbleY + $radius, $bubbleX + $bubbleWidth, $bubbleY + $bubbleHeight - $radius, $bubbleBgColor);
        
        // Corners
        imagefilledarc($canvas, $bubbleX + $radius, $bubbleY + $radius, $radius * 2, $radius * 2, 180, 270, $bubbleBgColor, IMG_ARC_PIE);
        imagefilledarc($canvas, $bubbleX + $bubbleWidth - $radius, $bubbleY + $radius, $radius * 2, $radius * 2, 270, 360, $bubbleBgColor, IMG_ARC_PIE);
        imagefilledarc($canvas, $bubbleX + $radius, $bubbleY + $bubbleHeight - $radius, $radius * 2, $radius * 2, 90, 180, $bubbleBgColor, IMG_ARC_PIE);
        imagefilledarc($canvas, $bubbleX + $bubbleWidth - $radius, $bubbleY + $bubbleHeight - $radius, $radius * 2, $radius * 2, 0, 90, $bubbleBgColor, IMG_ARC_PIE);
        
        // Draw pointer
        $pointerX = [$bubbleX, $bubbleX - 40, $bubbleX];
        $pointerY = [$bubbleY + $bubbleHeight/2 - 40, $bubbleY + $bubbleHeight/2, $bubbleY + $bubbleHeight/2 + 40];
        imagefilledpolygon($canvas, $pointerX, $pointerY, 3, $bubbleBgColor);
        
        // Border
        imagerectangle($canvas, $bubbleX + $radius, $bubbleY, $bubbleX + $bubbleWidth - $radius, $bubbleY + $bubbleHeight, $bubbleBorderColor);
        imagerectangle($canvas, $bubbleX, $bubbleY + $radius, $bubbleX + $bubbleWidth, $bubbleY + $bubbleHeight - $radius, $bubbleBorderColor);
        imagearc($canvas, $bubbleX + $radius, $bubbleY + $radius, $radius * 2, $radius * 2, 180, 270, $bubbleBorderColor);
        imagearc($canvas, $bubbleX + $bubbleWidth - $radius, $bubbleY + $radius, $radius * 2, $radius * 2, 270, 360, $bubbleBorderColor);
        imagearc($canvas, $bubbleX + $radius, $bubbleY + $bubbleHeight - $radius, $radius * 2, $radius * 2, 90, 180, $bubbleBorderColor);
        imagearc($canvas, $bubbleX + $bubbleWidth - $radius, $bubbleY + $bubbleHeight - $radius, $radius * 2, $radius * 2, 0, 90, $bubbleBorderColor);
        
        // Pointer border
        imagepolygon($canvas, $pointerX, $pointerY, 3, $bubbleBorderColor);
    }
}

// Set text area dimensions
$textAreaX = $bubbleX + $bubblePadding;
$textAreaY = $bubbleY + $bubblePadding;
$textAreaWidth = $bubbleWidth - ($bubblePadding * 2);
$textAreaHeight = $bubbleHeight - ($bubblePadding * 2);

// Word wrap the text
$words = explode(' ', $text);
$lines = [];
$currentLine = '';
$maxWidth = $textAreaWidth;

foreach ($words as $word) {
    $testLine = $currentLine . ' ' . $word;
    $testLine = ltrim($testLine); // Remove leading space
    
    // Calculate width using built-in or TTF font
    if (isset($config['use_builtin_font'])) {
        $textWidth = imagefontwidth(5) * strlen($testLine);
    } else {
        $bbox = imagettfbbox($config['font_size'], 0, $config['font'], $testLine);
        $textWidth = $bbox[2] - $bbox[0];
    }
    
    if ($textWidth > $maxWidth && $currentLine !== '') {
        $lines[] = $currentLine;
        $currentLine = $word;
    } else {
        $currentLine = $testLine;
    }
}
if ($currentLine !== '') {
    $lines[] = $currentLine;
}

// Center text vertically in the bubble
$lineCount = count($lines);
if (isset($config['use_builtin_font'])) {
    $totalTextHeight = $lineCount * imagefontheight(5);
} else {
    $totalTextHeight = $lineCount * $config['line_height'];
}

// Calculate vertical starting position for centered text
$startY = $textAreaY + ($textAreaHeight - $totalTextHeight) / 2;
if ($startY < $textAreaY) $startY = $textAreaY; // Ensure text doesn't overflow top

// Draw text
$y = $startY + $config['font_size']; // Start position for centered text
foreach ($lines as $line) {
    if (isset($config['use_builtin_font'])) {
        // Calculate width for centering horizontally
        $lineWidth = imagefontwidth(5) * strlen($line);
        $x = $textAreaX + ($textAreaWidth - $lineWidth) / 2;
        
        // Use built-in font (less nice but always available)
        imagestring($canvas, 5, $x, $y, $line, $textColor);
        $y += imagefontheight(5);
    } else {
        // Calculate width for centering horizontally
        $bbox = imagettfbbox($config['font_size'], 0, $config['font'], $line);
        $lineWidth = $bbox[2] - $bbox[0];
        $x = $textAreaX + ($textAreaWidth - $lineWidth) / 2;
        
        // Use TrueType font (nicer but requires font file)
        imagettftext($canvas, $config['font_size'], 0, $x, $y, $textColor, $config['font'], $line);
        $y += $config['line_height'];
    }
}

// Output the image
imagepng($canvas);

// Clean up
imagedestroy($canvas);