#include "game/drone.h"
#include "game/sprites.h"
#include "game/projectile.h"
#include "engine/renderer.h"
#include "engine/particle.h"
#include "engine/physics.h"
#include <stdlib.h>
#include <math.h>

#ifndef M_PI
#define M_PI 3.14159265358979323846
#endif

/* ── Stashed entity manager ────────────────────────── */
static EntityManager *s_em = NULL;

/* ── Helpers ───────────────────────────────────────── */

/* Find the active player entity */
static Entity *find_player(void) {
    if (!s_em) return NULL;
    for (int i = 0; i < s_em->count; i++) {
        Entity *e = &s_em->entities[i];
        if (e->active && e->type == ENT_PLAYER) return e;
    }
    return NULL;
}

/* Find nearest enemy within range */
static Entity *find_nearest_enemy(Vec2 from, float range) {
    if (!s_em) return NULL;
    Entity *best = NULL;
    float best_dist = range * range;
    for (int i = 0; i < s_em->count; i++) {
        Entity *e = &s_em->entities[i];
        if (!e->active || e->health <= 0) continue;
        if (e->type != ENT_ENEMY_GRUNT && e->type != ENT_ENEMY_FLYER &&
            e->type != ENT_TURRET) continue;
        Vec2 epos = vec2(e->body.pos.x + e->body.size.x * 0.5f,
                         e->body.pos.y + e->body.size.y * 0.5f);
        float dx = epos.x - from.x;
        float dy = epos.y - from.y;
        float dist2 = dx * dx + dy * dy;
        if (dist2 < best_dist) {
            best_dist = dist2;
            best = e;
        }
    }
    return best;
}

/* ── Callbacks ─────────────────────────────────────── */

static void drone_update(Entity *self, float dt, const Tilemap *map) {
    (void)map;
    DroneData *dd = (DroneData *)self->data;
    if (!dd) return;

    /* Countdown lifetime */
    dd->lifetime -= dt;
    if (dd->lifetime <= 0) {
        /* Expiry: death particles and destroy */
        Vec2 center = vec2(
            self->body.pos.x + self->body.size.x * 0.5f,
            self->body.pos.y + self->body.size.y * 0.5f
        );
        particle_emit_spark(center, (SDL_Color){50, 200, 255, 255});
        entity_destroy(s_em, self);
        return;
    }

    /* Follow player — orbit around player center */
    Entity *player = find_player();
    if (!player) return;

    Vec2 pcenter = vec2(
        player->body.pos.x + player->body.size.x * 0.5f,
        player->body.pos.y + player->body.size.y * 0.5f
    );

    dd->orbit_angle += DRONE_ORBIT_SPEED * dt;
    if (dd->orbit_angle > 2.0f * (float)M_PI)
        dd->orbit_angle -= 2.0f * (float)M_PI;

    float target_x = pcenter.x + cosf(dd->orbit_angle) * DRONE_ORBIT_RADIUS;
    float target_y = pcenter.y + sinf(dd->orbit_angle) * DRONE_ORBIT_RADIUS;

    /* Smooth movement toward orbit position */
    float lerp = 8.0f * dt;
    if (lerp > 1.0f) lerp = 1.0f;
    self->body.pos.x += (target_x - self->body.pos.x - self->body.size.x * 0.5f) * lerp;
    self->body.pos.y += (target_y - self->body.pos.y - self->body.size.y * 0.5f) * lerp;

    /* Shooting */
    dd->shoot_cooldown -= dt;
    if (dd->shoot_cooldown <= 0) {
        Vec2 drone_center = vec2(
            self->body.pos.x + self->body.size.x * 0.5f,
            self->body.pos.y + self->body.size.y * 0.5f
        );
        Entity *target = find_nearest_enemy(drone_center, DRONE_SHOOT_RANGE);
        if (target) {
            Vec2 tcenter = vec2(
                target->body.pos.x + target->body.size.x * 0.5f,
                target->body.pos.y + target->body.size.y * 0.5f
            );
            Vec2 dir = vec2(tcenter.x - drone_center.x, tcenter.y - drone_center.y);

            /* Spawn projectile from drone, counted as player bullet */
            projectile_spawn_def(s_em, &WEAPON_PLASMA,
                                 drone_center, dir, true);
            dd->shoot_cooldown = DRONE_SHOOT_CD;

            /* Muzzle flash */
            particle_emit_muzzle_flash(drone_center, dir);
        }
    }

    /* Trail particles — subtle engine glow */
    if ((int)(dd->lifetime * 10.0f) % 3 == 0) {
        Vec2 center = vec2(
            self->body.pos.x + self->body.size.x * 0.5f,
            self->body.pos.y + self->body.size.y * 0.5f
        );
        ParticleBurst b = {
            .origin     = center,
            .count      = 1,
            .speed_min  = 5.0f,
            .speed_max  = 15.0f,
            .life_min   = 0.1f,
            .life_max   = 0.3f,
            .size_min   = 1.0f,
            .size_max   = 1.5f,
            .spread     = (float)M_PI * 2.0f,
            .direction  = 0,
            .drag       = 3.0f,
            .gravity_scale = 0.0f,
            .color      = (SDL_Color){50, 180, 255, 150},
            .color_vary = true,
        };
        particle_emit(&b);
    }

    /* Blink when about to expire (last 3 seconds) */
    animation_update(&self->anim, dt);
}

static void drone_render(Entity *self, const Camera *cam) {
    (void)cam;
    DroneData *dd = (DroneData *)self->data;
    if (!dd) return;

    /* Blink when about to expire */
    if (dd->lifetime < 3.0f) {
        int blink = (int)(dd->lifetime * 8.0f);
        if (blink % 2 == 0) return;  /* skip rendering every other frame */
    }

    if (!g_spritesheet || !self->anim.def) return;

    SDL_Rect src = animation_current_rect(&self->anim);
    Body *body = &self->body;

    /* Center sprite on hitbox */
    float draw_x = body->pos.x + body->size.x * 0.5f - SPRITE_CELL * 0.5f;
    float draw_y = body->pos.y + body->size.y * 0.5f - SPRITE_CELL * 0.5f;

    Sprite spr = {
        .texture = g_spritesheet,
        .src     = src,
        .pos     = vec2(draw_x, draw_y),
        .size    = vec2(SPRITE_CELL, SPRITE_CELL),
        .flip_x  = false,
        .flip_y  = false,
        .layer   = LAYER_ENTITIES,
        .alpha   = 255,
    };
    renderer_submit(&spr);
}

static void drone_destroy(Entity *self) {
    free(self->data);
    self->data = NULL;
}

/* ── Public API ────────────────────────────────────── */

void drone_register(EntityManager *em) {
    entity_register(em, ENT_DRONE, drone_update, drone_render, drone_destroy);
    s_em = em;
}

Entity *drone_spawn(EntityManager *em, Vec2 player_pos) {
    Entity *e = entity_spawn(em, ENT_DRONE, player_pos);
    if (!e) return NULL;

    e->body.size = vec2(10.0f, 10.0f);
    e->body.gravity_scale = 0.0f;  /* floats freely */
    e->health = 99;       /* practically invulnerable */
    e->max_health = 99;
    e->damage = 0;
    e->flags |= ENTITY_INVINCIBLE | ENTITY_ALWAYS_UPDATE;

    DroneData *dd = calloc(1, sizeof(DroneData));
    dd->orbit_angle = 0.0f;
    dd->shoot_cooldown = 0.5f;  /* short initial delay */
    dd->lifetime = DRONE_DURATION;
    e->data = dd;

    animation_set(&e->anim, &anim_drone);

    /* Spawn burst */
    particle_emit_spark(player_pos, (SDL_Color){50, 200, 255, 255});

    printf("Drone deployed! (%0.0fs)\n", DRONE_DURATION);
    return e;
}
