#pragma once

#ifndef __INTELLISENSE__
#	define MODULE_EXPORT __attribute__( ( visibility( "default" ) ) )
#	define MODULE_WASM_MODNAME(mod) __attribute__((import_module(mod)))
#else
#	define MODULE_EXPORT
#	define MODULE_WASM_MODNAME(mod)
#	define __attribute__(x)
#	define __restrict__
#endif

/********************************* Headers *********************************/
// MSFS headers
#include <MSFS/MSFS_WindowsTypes.h>
#include <SimConnect.h>
// C headers
#include <math.h>
// C++ headers
#include <algorithm>
// Own headers
#include "shared.h"

/******************************** Constants ********************************/
//PMC pallet due to 104in door
#define MAX_UPPER_CARGO(IS_IMPERIAL) ((IS_IMPERIAL) ? (6.5 * 15000.0) : (6.5 * 6804.0))
// Max ZFW
#define MAX_F_ZFW(IS_IMPERIAL) ((IS_IMPERIAL) ? (451300) : (204706))
// Arms
#define ARM_F_UPPER1_LEFT 660
#define ARM_F_UPPER1_RIGHT 660
#define ARM_F_UPPER2_LEFT 240
#define ARM_F_UPPER2_RIGHT 240
#define ARM_F_UPPER3_LEFT -240
#define ARM_F_UPPER3_RIGHT -240
#define ARM_F_UPPER4_LEFT -600
#define ARM_F_UPPER4_RIGHT -600

/***************************** Data structures *****************************/
typedef struct {
    // SimConnect mapped
    double pilot;
    double firstOfficer;
    double engineer;
    double upper1Left;
    double upper1Right;
    double upper2Left;
    double upper2Right;
    double upper3Left;
    double upper3Right;
    double upper4Left;
    double upper4Right;
    double lowerForward;
    double lowerRear;
    double leftAux;
    double rightAux;

    // Additional properties
    double empty;
    double total;
    double CGTarget;
    double ZFWCG;
    double TOCG;
    struct stations {
        unsigned int upper1;
        unsigned int upper2;
        unsigned int upper3;
        unsigned int upper4;
        unsigned int total;
    } stations;
    struct sbPlanned {
        double ZFW;
        double GW;
        unsigned int cargo;
    } sbPlanned;
} fPayloadData_t;

typedef struct {
    // SimConnect mapped
    double pilot;
    double firstOfficer;
    double engineer;
    double upper1Left;
    double upper1Right;
    double upper2Left;
    double upper2Right;
    double upper3Left;
    double upper3Right;
    double upper4Left;
    double upper4Right;
    double lowerForward;
    double lowerRear;
    double leftAux;
    double rightAux;
} fPayloadDataSet_t;

/******************************** Functions ********************************/
// ZFW Entry
void distribute(fPayloadData_t* const targetPayload, const FuelData_t* const fuel, const double ZFWTarget, const UserData_t* const userData);
// SimBrief Entry
void distribute(fPayloadData_t* const targetPayload, const FuelData_t* const fuel, unsigned int cargo, const UserData_t* const userData);
// Updates pax stations with their respective weights
// Used internally and used for Station Entry (pax only, cargo is ste directly)
// STATION WEIGHTS ARE NOT NORMALISED TO POUNDS
void generatePayload(fPayloadData_t* const targetPayload, const bool isImperial);
// Normalise to Pounds
// For Station Entry: CALL AFTER `generatePayload`
void normalisePayload(fPayloadData_t* const targetPayload, const bool isImperial);
void calculateCGs(const fPayloadData_t* const targetPayload, const FuelData_t* const fuel, double* const ZFWCG, double* const TOCG, const bool isImperial);
void load(const fPayloadData_t* const targetPayload, const HANDLE simConnect, const bool isImperial);
void unloadF(const HANDLE simConnect, const bool isER);
