// LineEffect.cpp - Implementation of line clearing visual and audio effects
#include "LineEffect.h"
#include <algorithm>
#include <cmath>
#include "audio/Audio.h"
#include "audio/AudioManager.h"

#ifndef M_PI
#define M_PI 3.14159265358979323846
#endif

LineEffect::Particle::Particle(float px, float py) 
    : x(px), y(py), size(1.5f + static_cast<float>(rand()) / RAND_MAX * 4.0f), alpha(1.0f) {
    
    // Random velocity for explosive effect
    float angle = static_cast<float>(rand()) / RAND_MAX * 2.0f * M_PI;
    float speed = 80.0f + static_cast<float>(rand()) / RAND_MAX * 150.0f; // More explosive speed
    vx = std::cos(angle) * speed;
    vy = std::sin(angle) * speed - 30.0f; // Less upward bias for more spread
    
    // Bright explosive colors (oranges, yellows, whites, reds)
    int colorType = rand() % 4;
    switch (colorType) {
        case 0: // Orange/Fire
            color = {255, static_cast<Uint8>(140 + rand() % 100), static_cast<Uint8>(30 + rand() % 50), 255};
            break;
        case 1: // Yellow/Gold
            color = {255, 255, static_cast<Uint8>(100 + rand() % 155), 255};
            break;
        case 2: // White
            color = {255, 255, 255, 255};
            break;
        case 3: // Red/Pink
            color = {255, static_cast<Uint8>(100 + rand() % 100), static_cast<Uint8>(100 + rand() % 100), 255};
            break;
    }
}

void LineEffect::Particle::update() {
    x += vx * 0.016f; // Assume ~60 FPS
    y += vy * 0.016f;
    vy += 250.0f * 0.016f; // Stronger gravity for explosive effect
    vx *= 0.98f; // Air resistance
    alpha -= 0.12f; // Fast fade for explosive burst
    if (alpha < 0.0f) alpha = 0.0f;
    
    // Shrink particles as they fade
    if (size > 0.5f) size -= 0.05f;
}

void LineEffect::Particle::render(SDL_Renderer* renderer) {
    if (alpha <= 0.0f) return;
    
    SDL_SetRenderDrawBlendMode(renderer, SDL_BLENDMODE_BLEND);
    Uint8 adjustedAlpha = static_cast<Uint8>(alpha * 255.0f);
    SDL_SetRenderDrawColor(renderer, color.r, color.g, color.b, adjustedAlpha);
    
    // Draw particle as a small circle
    for (int i = 0; i < static_cast<int>(size); ++i) {
        for (int j = 0; j < static_cast<int>(size); ++j) {
            float dx = i - size/2.0f;
            float dy = j - size/2.0f;
            if (dx*dx + dy*dy <= (size/2.0f)*(size/2.0f)) {
                SDL_RenderPoint(renderer, x + dx, y + dy);
            }
        }
    }
}

LineEffect::LineEffect() : renderer(nullptr), state(AnimationState::IDLE), timer(0.0f), 
                          rng(std::random_device{}()), audioStream(nullptr) {
}

LineEffect::~LineEffect() {
    shutdown();
}

bool LineEffect::init(SDL_Renderer* r) {
    renderer = r;
    initAudio();
    return true;
}

void LineEffect::shutdown() {
    // No separate audio stream anymore; SFX go through shared Audio mixer
}

void LineEffect::initAudio() {
    // Generate simple beep sounds procedurally (fallback when voice SFX not provided)
    
    // Generate a simple line clear beep (440Hz for 0.2 seconds)
    int sampleRate = 44100;
    int duration = static_cast<int>(0.2f * sampleRate);
    lineClearSample.resize(duration * 2); // Stereo
    
    for (int i = 0; i < duration; ++i) {
        float t = static_cast<float>(i) / sampleRate;
        float wave = std::sin(2.0f * M_PI * 440.0f * t) * 0.3f; // 440Hz sine wave
        int16_t sample = static_cast<int16_t>(wave * 32767.0f);
        lineClearSample[i * 2] = sample;     // Left channel
        lineClearSample[i * 2 + 1] = sample; // Right channel
    }
    
    // Generate a higher pitched tetris sound (880Hz for 0.4 seconds)
    duration = static_cast<int>(0.4f * sampleRate);
    tetrisSample.resize(duration * 2);
    
    for (int i = 0; i < duration; ++i) {
        float t = static_cast<float>(i) / sampleRate;
        float wave = std::sin(2.0f * M_PI * 880.0f * t) * 0.4f; // 880Hz sine wave
        int16_t sample = static_cast<int16_t>(wave * 32767.0f);
        tetrisSample[i * 2] = sample;     // Left channel
        tetrisSample[i * 2 + 1] = sample; // Right channel
    }
}

void LineEffect::startLineClear(const std::vector<int>& rows, int gridX, int gridY, int blockSize) {
    if (rows.empty()) return;
    
    clearingRows = rows;
    state = AnimationState::FLASH_WHITE;
    timer = 0.0f;
    particles.clear();
    
    // Create particles for each clearing row
    for (int row : rows) {
        createParticles(row, gridX, gridY, blockSize);
    }
    
    // Play appropriate sound
    playLineClearSound(static_cast<int>(rows.size()));
}

void LineEffect::createParticles(int row, int gridX, int gridY, int blockSize) {
    // Create particles spread across the row with explosive pattern
    int particlesPerRow = 35; // More particles for dramatic explosion effect
    
    for (int i = 0; i < particlesPerRow; ++i) {
        // Create particles along the entire row width
        float x = gridX + (static_cast<float>(i) / (particlesPerRow - 1)) * (10 * blockSize);
        float y = gridY + row * blockSize + blockSize / 2.0f;
        
        // Add some randomness to position
        x += (static_cast<float>(rand()) / RAND_MAX - 0.5f) * blockSize * 0.8f;
        y += (static_cast<float>(rand()) / RAND_MAX - 0.5f) * blockSize * 0.6f;
        
        particles.emplace_back(x, y);
    }
}

bool LineEffect::update(float deltaTime) {
    if (state == AnimationState::IDLE) return true;
    
    timer += deltaTime;
    
    switch (state) {
        case AnimationState::FLASH_WHITE:
            if (timer >= FLASH_DURATION) {
                state = AnimationState::EXPLODE_BLOCKS;
                timer = 0.0f;
            }
            break;
            
        case AnimationState::EXPLODE_BLOCKS:
            updateParticles();
            if (timer >= EXPLODE_DURATION) {
                state = AnimationState::BLOCKS_DROP;
                timer = 0.0f;
            }
            break;
            
        case AnimationState::BLOCKS_DROP:
            updateParticles();
            if (timer >= DROP_DURATION) {
                state = AnimationState::IDLE;
                clearingRows.clear();
                particles.clear();
                return true; // Effect complete
            }
            break;
            
        case AnimationState::IDLE:
            return true;
    }
    
    return false; // Effect still running
}

void LineEffect::updateParticles() {
    // Update all particles
    for (auto& particle : particles) {
        particle.update();
    }
    
    // Remove dead particles
    particles.erase(
        std::remove_if(particles.begin(), particles.end(),
                      [](const Particle& p) { return !p.isAlive(); }),
        particles.end()
    );
}

void LineEffect::render(SDL_Renderer* renderer, int gridX, int gridY, int blockSize) {
    if (state == AnimationState::IDLE) return;
    
    switch (state) {
        case AnimationState::FLASH_WHITE:
            renderFlash(gridX, gridY, blockSize);
            break;
            
        case AnimationState::EXPLODE_BLOCKS:
            renderExplosion();
            break;
            
        case AnimationState::BLOCKS_DROP:
            renderExplosion();
            break;
            
        case AnimationState::IDLE:
            break;
    }
}

void LineEffect::renderFlash(int gridX, int gridY, int blockSize) {
    // Create a flashing white effect with varying opacity
    float progress = timer / FLASH_DURATION;
    float flashIntensity = std::sin(progress * M_PI * 6.0f) * 0.5f + 0.5f; // Fewer flashes for quicker effect
    
    SDL_SetRenderDrawBlendMode(renderer, SDL_BLENDMODE_BLEND);
    Uint8 alpha = static_cast<Uint8>(flashIntensity * 180.0f); // Slightly less intense
    
    for (int row : clearingRows) {
        // Draw white rectangle covering the entire row with blue glow effect
        SDL_SetRenderDrawColor(renderer, 255, 255, 255, alpha);
        
        SDL_FRect flashRect = {
            static_cast<float>(gridX - 4),
            static_cast<float>(gridY + row * blockSize - 4),
            static_cast<float>(10 * blockSize + 8),
            static_cast<float>(blockSize + 8)
        };
        
        SDL_RenderFillRect(renderer, &flashRect);
        
        // Add blue glow border
        SDL_SetRenderDrawColor(renderer, 100, 150, 255, alpha / 2);
        for (int i = 1; i <= 3; ++i) {
            SDL_FRect glowRect = {
                flashRect.x - i,
                flashRect.y - i,
                flashRect.w + 2*i,
                flashRect.h + 2*i
            };
            SDL_RenderRect(renderer, &glowRect);
        }
    }
}

void LineEffect::renderExplosion() {
    for (auto& particle : particles) {
        particle.render(renderer);
    }
}

void LineEffect::playLineClearSound(int lineCount) {
    // Choose appropriate sound based on line count
    const std::vector<int16_t>* sample = (lineCount == 4) ? &tetrisSample : &lineClearSample;
    if (sample && !sample->empty()) {
        // Mix via shared Audio device so it layers with music
        if (auto sys = AudioManager::get()) sys->playSfx(*sample, 2, 44100, (lineCount == 4) ? 0.9f : 0.7f);
    }
}
