#include "app/Fireworks.h"
#include <SDL3/SDL.h>
#include <vector>
#include <cstdlib>
#include <cmath>
#include <algorithm>

namespace {
struct BlockParticle {
    float x{}, y{}, vx{}, vy{}, size{}, alpha{}, decay{}, wobblePhase{}, wobbleSpeed{}, coreHeat{};
    BlockParticle(float sx, float sy) : x(sx), y(sy) {
        const float spreadDeg = 35.0f;
        const float angleDeg = -90.0f + spreadDeg * ((rand() % 200) / 100.0f - 1.0f);
        const float angleRad = angleDeg * 3.1415926f / 180.0f;
        float speed = 1.3f + (rand() % 220) / 80.0f;
        vx = std::cos(angleRad) * speed * 0.55f;
        vy = std::sin(angleRad) * speed;
        size = 6.0f + (rand() % 40) / 10.0f;
        alpha = 1.0f;
        decay = 0.0095f + (rand() % 180) / 12000.0f;
        wobblePhase = (rand() % 628) / 100.0f;
        wobbleSpeed = 0.08f + (rand() % 60) / 600.0f;
        coreHeat = 0.65f + (rand() % 35) / 100.0f;
    }
    bool update() {
        vx *= 0.992f;
        vy = vy * 0.985f - 0.015f;
        x += vx;
        y += vy;
        wobblePhase += wobbleSpeed;
        x += std::sin(wobblePhase) * 0.12f;
        alpha -= decay;
        size = std::max(1.8f, size - 0.03f);
        coreHeat = std::max(0.0f, coreHeat - decay * 0.6f);
        return alpha > 0.03f;
    }
};

struct TetrisFirework {
    std::vector<BlockParticle> particles;
    TetrisFirework(float x, float y) {
        int particleCount = 30 + rand() % 25;
        particles.reserve(particleCount);
        for (int i=0;i<particleCount;++i) particles.emplace_back(x,y);
    }
    bool update() {
        for (auto it = particles.begin(); it != particles.end();) {
            if (!it->update()) it = particles.erase(it);
            else ++it;
        }
        return !particles.empty();
    }
};

static std::vector<TetrisFirework> fireworks;
static double logoAnimCounter = 0.0;
static int hoveredButton = -1;

static SDL_Color blendFireColor(float heat, float alphaScale, Uint8 minG, Uint8 minB) {
    heat = std::clamp(heat, 0.0f, 1.0f);
    Uint8 r = 255;
    Uint8 g = static_cast<Uint8>(std::clamp(120.0f + heat * (255.0f - 120.0f), float(minG), 255.0f));
    Uint8 b = static_cast<Uint8>(std::clamp(40.0f + (1.0f - heat) * 60.0f, float(minB), 255.0f));
    Uint8 a = static_cast<Uint8>(std::clamp(alphaScale * 255.0f, 0.0f, 255.0f));
    return SDL_Color{r,g,b,a};
}
} // namespace

namespace AppFireworks {
void update(double frameMs) {
    if (fireworks.size() < 5 && (rand() % 100) < 2) {
        float x = 1200.0f * 0.55f + float(rand() % int(1200.0f * 0.35f));
        float y = 1000.0f * 0.80f + float(rand() % int(1000.0f * 0.15f));
        fireworks.emplace_back(x,y);
    }
    for (auto it = fireworks.begin(); it != fireworks.end();) {
        if (!it->update()) it = fireworks.erase(it);
        else ++it;
    }
}

void draw(SDL_Renderer* renderer, SDL_Texture*) {
    if (!renderer) return;
    SDL_BlendMode previousBlend = SDL_BLENDMODE_NONE;
    SDL_GetRenderDrawBlendMode(renderer, &previousBlend);
    SDL_SetRenderDrawBlendMode(renderer, SDL_BLENDMODE_ADD);
    static constexpr int quadIdx[6] = {0,1,2,2,1,3};

    auto makeV = [](float px, float py, SDL_Color c){
        SDL_Vertex v{};
        v.position.x = px;
        v.position.y = py;
        v.color = SDL_FColor{ c.r/255.0f, c.g/255.0f, c.b/255.0f, c.a/255.0f };
        return v;
    };

    for (auto& f : fireworks) {
        for (auto& p : f.particles) {
            const float heat = std::clamp(p.alpha * 1.25f + p.coreHeat * 0.5f, 0.0f, 1.0f);
            SDL_Color glow = blendFireColor(0.45f + heat * 0.55f, p.alpha * 0.55f, 100, 40);
            SDL_Color tailBase = blendFireColor(heat * 0.75f, p.alpha * 0.5f, 70, 25);
            SDL_Color tailTip = blendFireColor(heat * 0.35f, p.alpha * 0.2f, 40, 15);
            SDL_Color core = blendFireColor(heat, std::min(1.0f, p.alpha * 1.1f), 150, 80);

            float velLen = std::sqrt(p.vx*p.vx + p.vy*p.vy);
            SDL_FPoint dir = velLen > 0.001f ? SDL_FPoint{p.vx/velLen,p.vy/velLen} : SDL_FPoint{0.0f,-1.0f};
            SDL_FPoint perp{-dir.y, dir.x};
            const float baseW = std::max(0.8f, p.size * 0.55f);
            const float tipW = baseW * 0.35f;
            const float tailLen = p.size * (3.0f + (1.0f - p.alpha) * 1.8f);

            SDL_FPoint base{p.x,p.y};
            SDL_FPoint tip{p.x + dir.x*tailLen, p.y + dir.y*tailLen};

            SDL_Vertex tail[4];
            tail[0] = makeV(base.x + perp.x * baseW, base.y + perp.y * baseW, tailBase);
            tail[1] = makeV(base.x - perp.x * baseW, base.y - perp.y * baseW, tailBase);
            tail[2] = makeV(tip.x + perp.x * tipW, tip.y + perp.y * tipW, tailTip);
            tail[3] = makeV(tip.x - perp.x * tipW, tip.y - perp.y * tipW, tailTip);
            SDL_RenderGeometry(renderer, nullptr, tail, 4, quadIdx, 6);

            const float glowAlong = p.size * 0.95f;
            const float glowAcross = p.size * 0.6f;
            SDL_Vertex glowV[4];
            glowV[0] = makeV(base.x + dir.x * glowAlong, base.y + dir.y * glowAlong, glow);
            glowV[1] = makeV(base.x - dir.x * glowAlong, base.y - dir.y * glowAlong, glow);
            glowV[2] = makeV(base.x + perp.x * glowAcross, base.y + perp.y * glowAcross, glow);
            glowV[3] = makeV(base.x - perp.x * glowAcross, base.y - perp.y * glowAcross, glow);
            SDL_RenderGeometry(renderer, nullptr, glowV, 4, quadIdx, 6);

            const float coreW = p.size * 0.35f;
            const float coreH = p.size * 0.9f;
            SDL_Vertex coreV[4];
            coreV[0] = makeV(base.x + perp.x * coreW, base.y + perp.y * coreW, core);
            coreV[1] = makeV(base.x - perp.x * coreW, base.y - perp.y * coreW, core);
            coreV[2] = makeV(base.x + dir.x * coreH, base.y + dir.y * coreH, core);
            coreV[3] = makeV(base.x - dir.x * coreH, base.y - dir.y * coreH, core);
            SDL_RenderGeometry(renderer, nullptr, coreV, 4, quadIdx, 6);
        }
    }

    SDL_SetRenderDrawBlendMode(renderer, previousBlend);
}

double getLogoAnimCounter() { return logoAnimCounter; }
int getHoveredButton() { return hoveredButton; }
void spawn(float x, float y) {
    fireworks.emplace_back(x, y);
}
} // namespace AppFireworks
