#pragma once
#include <SDL3/SDL.h>
#include "misc.h"
#include "jdraw.h"
#include <vector>
#include <string>

// Flags que defineixen les capacitats de l'actor
#define FLAG_NONE 0
#define FLAG_HERO 1        // Es el heroi
#define FLAG_PUSHABLE 2    // Es pot espentar
#define FLAG_REACTIVE 4    // Quan se li espenta, torna una espenta específica
#define FLAG_MOVING 8      // Es mou
#define FLAG_ANIMATED 16   // Te animació de frames
#define FLAG_ORIENTABLE 32 // S'orienta cap on va
#define FLAG_DEADLY 64     // Fa pupa
#define FLAG_GRAVITY 128   // Li afecta la gravetat
#define FLAG_PICKABLE 256  // Es pot agafar
#define FLAG_SPECIAL 512   // Especial (habilitats, poders temporals i parts de l'excavadora)
#define FLAG_NOEDITOR 1024 // No es seleccionable a l'editor (son les portes)
#define FLAG_INERTIA 2048  // Al rebre una espenta, continua fins tropesar en algo
#define FLAG_DISAPPEAR 4096  // Al tocar-lo, desapareix

#define FLAG_SENSIBLE 6  // PUSHABLE or REACTIVE
#define FLAG_IGNORE 1025 // HERO or NOEDITOR

// Direcció de espenta
#define PUSH_NONE 0
#define PUSH_XP 1
#define PUSH_XN 2
#define PUSH_YP 4
#define PUSH_YN 8
#define PUSH_ZP 16
#define PUSH_ZN 32
#define PUSH_KILL 64
#define PUSH_DOUBLE 128

// Tipus de moviment de l'actor
#define MOV_NONE 0  // Ningun
#define MOV_X 1     // Es mou només en l'eix X i quan topeta en algo, torna per on venia
#define MOV_Y 2     // Es mou només en l'eix Y i quan topeta en algo, torna per on venia
#define MOV_Z 3     // Es mou només en l'eix Z i quan topeta en algo, torna per on venia
#define MOV_CW 4    // Es mou en sentit de les agulles del rellotge
#define MOV_CCW 5   // Es mou en sentit contrari a les agulles del rellotge
#define MOV_RAND 6  // Es mou en direcció aleatòria
#define MOV_RANDV 7 // Es mou en direcció aleatòria, diagonals incloses
#define MOV_HUNT 8  // Persegueix al heroi
#define MOV_RANDJ 9 // Es mou en direcció aleatòria, diagonals incloses, pegant botets

// Boosters
#define BOOST_NONE 0
#define BOOST_RUN 1
#define BOOST_GOD 2
#define BOOST_JUMP 4
#define BOOST_LIVE 8

// Skills
#define SKILL_NONE 0
#define SKILL_SHOES 1
#define SKILL_GLOVES 2
#define SKILL_PANTS 4
#define SKILL_BAG 8

// Parts
#define PART_NONE 0
#define PART_FILTER 1
#define PART_PUMP 2
#define PART_TIMER 4
#define PART_SALT 8
#define PART_PIPE 16
#define PART_ELBOW 32

namespace actor
{
    struct actor_t
    {
        char name[16];
        draw::surface *surface;
        char bmp[16];
        SDL_Rect bmp_rect;
        SDL_Point bmp_offset;

        vec3_t pos;
        vec3_t size;

        int orient;
        int anim_cycle;
        int anim_frame;
        int anim_wait;
        int anim_wait_count;

        int flags;
        int push;

        int react_mask;
        int react_push;

        int movement;
        int mov_push;

        actor_t *below;
        actor_t *above;

        actor_t *prev;
        actor_t *next;
        actor_t *next_alpha;

        int inner_x;
        int inner_y;

        int tag;
        int template_category;
        bool alive;
    };

    void resetTag();

    // Torna el primer actor de la llista
    actor_t *getFirst();

    // Torna l'últim actor de la llista
    actor_t *getLast();

    // Torna el actor seleccionat a l'editor
    actor_t *getSelected();

    // Torna un nou actor
    actor_t *create(std::string name, vec3_t p, vec3_t s, std::string bmp, SDL_Rect r, SDL_Point o);

    actor_t *createEmptyActor();

    actor_t *duplicate(actor_t *act);

    actor_t *createFromTemplate(const char *name);

    actor_t *createFromFile(char **buffer);

    actor_t *replaceWithTemplate(actor_t *act, const char *name);

    void cleanName(actor_t *act);

    void setUniqueName(actor_t *act);

    actor_t *alphaOrder(actor_t *act);

    void saveToFile(FILE *f, actor_t *act, bool tab=false);

    void setDirty(actor_t *act, const bool force = false);

    void select(actor_t *act);

    void reorder();

    uint8_t push(actor_t *source, actor_t *act, uint8_t push);

    void update(actor_t *act, const bool update_all = true);
    void updateEditor(actor_t *act, const bool update_all = true);

    void drawAt(actor_t *act, const int x, const int y);
    void draw(actor_t *act, const bool draw_all = true);

    actor_t *find(std::string name);

    actor_t *findByTag(const int tag);

    actor_t *find_at(const int x, const int y, const int z);

    actor_t *get_collision(actor_t *act);

    const bool check_collision(actor_t *obj1, actor_t *obj2);

    void remove(actor_t *act);

    void sendToPurgatory(actor_t *act);

    void cleanPurgatory();

    void pick(actor_t *act);

    actor_t *getPicked();

    void clear(const bool all = false);

    void setFloatingEditing(const bool value);

    const bool getFloatingEditing();

    void pauseWalkSound();

    namespace templates
    {
        void load();
        void save();
        //const int size();
        std::vector<actor::actor_t> getByCategory(const char* category);
        std::vector<std::string> getCategories();
        const int newCategory(const char *name);
        actor_t *get(const int index);
        actor_t *getByName(const char *name);
        void copy(actor_t *dest, actor_t *source);
        void add(actor_t *act);
        void swapCategories(const int a, const int b);
    }

    namespace hero
    {
        #define PROLOGO_OBJECT_INITIAL 0
        #define PROLOGO_OBJECT_PICKED  1
        #define PROLOGO_OBJECT_LEFT    2

        #define PROLOGO_SHOES  0
        #define PROLOGO_PANTS  1
        #define PROLOGO_GLOVES 2
        #define PROLOGO_BAG    3

        void setPrologo(const bool value);
        const bool isPrologo();
        void init(const bool complete = true);
        int getLives();
        void setLives(int value);

        void die();
        bool isDead();

        const int getBoosterFromString(const char *booster);
        const char *getBoosterName(int booster);
        bool giveBooster(char *booster);
        void collectBooster(const char *booster, int id);
        bool wasBoosterCollected(int id);
        int getBoostGod();
        int getBoostRun();
        int getBoostJump();
        void useBoostGod();
        void useBoostRun();
        void useBoostJump();
        const bool hasBoostGod();

        const int getSkillFromString(char *skill);
        const char *getSkillName(int skill);
        bool giveSkill(int skill);
        bool giveSkill(char *skill);
        bool dropSkill(int skill);
        bool dropSkill(char *skill);
        bool wasSkillCollected(char *skill);
        int getSkills();

        const int getPartFromString(char *part);
        const char *getPartName(int part);
        bool pickPart(char *part);
        bool dropPart(char *part);
        bool wasPartCollected(char *part);
        int getParts();

        void pickAnbernic(char *name);
        bool wasAnbernicCollected(char *name);
        int getNumAmbernicsCollected();

        void pickPrologoObject(int which);
        void leavePrologoObject(int which);
        const bool isCarryingPrologoObject();
        const int getPrologoObjectState(int which);
        const int getNumPrologoObjectsDone();
        
        void move(int *x, int *y, int *z);
        void setFirstPos();
    }

    namespace stats
    {
        void reset();

        void collectPart();
        void visitRoom(int room);
        void loseLive();

        int getNumPartsCollected();
        int getRoomsVisited();
        uint32_t getStartTime();
        int getLivesLost();

        bool catsLife();
    }
}