#pragma once
#include "lephisto.h"
#include "physics.h"
#include "ai.h"
#include "outfit.h"
#include "faction.h"
#include "sound.h"
#include "economy.h"
#include "ship.h"

#define PLAYER_ID 1

#define HYPERSPACE_ENGINE_DELAY   3000  // Warm up the engines.
#define HYPERSPACE_FLY_DELAY      5000  // Time taken to hyperspace.
#define HYPERSPACE_STARS_BLUR     2000  // Time stars blur.
#define HYPERSPACE_STARS_LENGTH   1000  // Length the stars blur to at max.
#define HYPERSPACE_FADEOUT        1000  // Time fadeout.

// Aproximation for pilot size.
#define PILOT_SIZE_APROX          0.8
#define PILOT_DISABLED_ARMOUR     0.3   // Based on armour percentage.

// Hooks.
#define PILOT_HOOK_NONE           0     // No hook.
#define PILOT_HOOK_DEATH          1     // Pilot died.

// Flags.
#define pilot_isFlag(p,f)   (p->flags & (f))
#define pilot_setFlag(p,f)  (p->flags |= (f))
#define pilot_rmFlag(p,f)   (p->flags ^= (f))
// Creation.
#define PILOT_PLAYER        (1<<0)  // Pilot is a player.
#define PILOT_HASTURRET     (1<<20) // Pilot has turrets.
#define PILOT_NO_OUTFITS    (1<<21) // Do not create the pilot with outfits.
#define PILOT_EMPTY         (1<<22) // Do not add pilot to stack.
// Dynamic.
#define PILOT_HOSTILE       (1<<1)  // Pilot is hostile to the player.
#define PILOT_COMBAT        (1<<2)  // Pilot is engaged in combat.
#define PILOT_AFTERBURNER   (1<<3)  // Pilot has her afterburner activated.
#define PILOT_HYP_PREP      (1<<5)  // Pilot is getting ready for hyperspace.
#define PILOT_HYP_BEGIN     (1<<6)  // Pilot is starting engines.
#define PILOT_HYPERSPACE    (1<<7)  // Pilot is in hyperspace.
#define PILOT_BOARDED       (1<<8)  // Pilot has been boarded already!
#define PILOT_DISABLED      (1<<9)  // Pilot is disabled.
#define PILOT_DEAD          (1<<10) // Pilot is on it's death bed.
#define PILOT_EXPLODED      (1<<11) // Pilot did final death explosion.
#define PILOT_DELETE        (1<<15) // Pilot will get delete asap.

// Just makes life simpler.
#define pilot_isPlayer(p)   ((p)->flags & PILOT_PLAYER)
#define pilot_isDisabled(p) ((p)->flags & PILOT_DISABLED)

typedef struct PilotOutfit_ {
  Outfit* outfit;     // Associated outfit.
  int quantity;       // Number of outfits of this type that the pilot has.
  unsigned int timer; // Used to store last used weapon time.
} PilotOutfit;

// Pilot commodity.
typedef struct PilotCommodity_ {
  Commodity* commodity;
  int quantity;
  unsigned int id;  // Special mission id for cargo.
} PilotCommodity;

// Primary pilot structure.
typedef struct Pilot_ {
  unsigned int id;  // Pilots id.
  char* name;       // Pilot's name (if unique).

  int faction;

  // Object characteristics.
  Ship* ship;     // Pilots ship.
  Solid* solid;   // Associated solid (physics).
  int tsx, tsy;   // Current sprite, calculated on update.

  double thrust, turn, speed;

  // Current health.
  double armour, shield, energy;
  double armour_max, shield_max, energy_max;
  double armour_regen, shield_regen, energy_regen;
  double fuel; // Used only for jumps. TODO: make it do something.

  void (*think)(struct Pilot_*); // AI thinking for the pilot.
  void (*update)(struct Pilot_*, const double); // Update the pilot.
  void (*render)(struct Pilot_*); // Rendering the pilot.

  // Outfit management.
  PilotOutfit* outfits;
  int noutfits;
  PilotOutfit* secondary;   // Secondary weapon.
  PilotOutfit* ammo;        // Secondary ammo (if needed).
  PilotOutfit* afterburner; // Ze afterburner.

  // Cargo.
  int credits; // Moniez the pilot has.
  PilotCommodity* commodities; // Commodity and quantity.
  int ncommodities;
  int cargo_free;

  // Misc.
  uint32_t flags; // Used for AI etc.
  unsigned int ptimer;  // Generic timer for internal pilot use.

  // Hook attached to the pilot.
  int hook_type;
  int hook;

  // AI.
  AI_Profile* ai; // Ai personality profile.
  unsigned int tcontrol; // Timer for control tick.
  unsigned int timer[MAX_AI_TIMERS]; // Timers for AI.
  Task* task; // Current action.
} Pilot;

// Fleets.
typedef struct FleetPilot_ {
  Ship* ship; // Ship that the pilot is flying.
  char* name; // For special 'unique' names.
  int chance; // Chance of this pilot appearing in the fleet.
} FleetPilot;

typedef struct Fleet_ {
  char* name;   // Fleet name, used as an identifier.
  int faction;  // Faction of the fleet.

  AI_Profile* ai; // A useable profile.

  FleetPilot* pilots; // The pilots in the fleet.
  int npilots; // Total number of pilots.
} Fleet;

// Grabing pilot crap.
extern Pilot* player; // The player.
Pilot* pilot_get(unsigned int id);
unsigned int pilot_getNext(const unsigned int id);
unsigned int pilot_getNearest(const Pilot* p);
unsigned int pilot_getHostile(void); // Only for the player.
Fleet* fleet_get(const char* name);

// MISC.
void pilot_shoot(Pilot* p, const unsigned int target, const int secondary);
void pilot_hit(Pilot* p, const Solid* w, const unsigned int shooter,
               const double damage_shield, const double damage_armour);
void pilot_setSecondary(Pilot* p, const char* secondary);
void pilot_setAmmo(Pilot* p);
double pilot_face(Pilot* p, const float dir);
// Outfits.
int pilot_freeSpace(Pilot* p); // Pilot space.
int pilot_addOutfit(Pilot* pilot, Outfit* outfit, int quantity);
int pilot_rmOutfit(Pilot* pilot, Outfit* outfit, int quantity);
char* pilot_getOutfits(Pilot* pilot);
// Normal cargo.
int pilot_freeCargo(Pilot* p); // Cargo space.
int pilot_addCargo(Pilot* pilot, Commodity* cargo, int quantity);
int pilot_rmCargo(Pilot* pilot, Commodity* cargo, int quantity);
// Mission cargo - Not to be confused with normal cargo.
unsigned int pilot_addMissionCargo(Pilot* pilot, Commodity* cargo, int quantity);
int pilot_rmMissionCargo(Pilot* pilot, unsigned int cargo_id);


// Creation.
void pilot_init(Pilot* dest, Ship* ship, char* name, int faction,
                AI_Profile* ai, const double dir, const Vec2* pos,
                const Vec2* vel, const int flags);

unsigned int pilot_create(Ship* ship, char* name, int faction,
                          AI_Profile* ai, const double dir, const Vec2* pos,
                          const Vec2* vel, const int flags);

Pilot* pilot_createEmpty(Ship* ship, char* name,
                         int faction, AI_Profile* ai, const int flags);

Pilot* pilot_copy(Pilot* src);

// Init/Cleanup.
void pilot_destroy(Pilot* p);
void pilots_free(void);
void pilots_clean(void);
void pilot_free(Pilot* p);
int fleet_load(void); // TODO
void fleet_free(void);

// Update.
void pilots_update(double dt);
void pilots_render(void);

void pilot_addHook(Pilot* pilot, int type, int hook);