#include <stdint.h>
#include <stdbool.h>
#include "common.hpp"
#include <cstring>
#include <list>
#include <fstream>
#include <vector>
#include <iostream>

#define SAVE_FORMAT 1

bool creative_mode = false;
float player_health = MAX_HP;
float player_attack_time = 0;
float player_place_time = 0;
float player_break_parts_time = 0;
Vector3 player_position;
Vector3 player_velocity;
int GetItemNumID(std::string s);

extern InventoryItem hotbar[ITEMS];
extern InventoryItem inventory[INVENTORY_SIZE];
extern std::vector<Item> registry;

void SavePlayerData() {
    std::ofstream data(PathifyUser("player.data"), std::ios::binary);
    if (!data) return;

    data.write("PLR", 3);
    char fmt = static_cast<char>(SAVE_FORMAT);
    data.write(&fmt, 1);
    char creative = static_cast<char>(creative_mode);
    data.write(&creative, 1);
    data.write(reinterpret_cast<const char*>(&player_health), sizeof(player_health));

    std::cout << "H" << std::endl;
    std::vector<uint8_t> temp;

    for (int i = 0; i < ITEMS; i++)
    {
        Item* item = hotbar[i].item;
        int id = 0;
        if(item != nullptr)
            id = GetItemNumID(item->id);
        std::cout << inventory[i].amount << std::endl;
        temp.push_back((uint8_t)id);
        temp.push_back((uint8_t)hotbar[i].damage);
        temp.push_back((uint8_t)hotbar[i].amount);
    }
    for (int i = 0; i < INVENTORY_SIZE; i++)
    {
        Item* item = inventory[i].item;
        int id = 0;
        if(item != nullptr)
            id = GetItemNumID(item->id);
        temp.push_back((uint8_t)id);
        temp.push_back((uint8_t)inventory[i].damage);
        temp.push_back((uint8_t)inventory[i].amount);
    }
    uint16_t size = static_cast<uint16_t>(temp.size());
    data.write(reinterpret_cast<const char*>(&size), sizeof(size));
    if (!temp.empty()) {
        data.write(reinterpret_cast<const char*>(temp.data()), temp.size());
    }
}

bool LoadPlayerData() {
    std::ifstream data(PathifyUser("player.data"), std::ios::binary);
    if (!data) return false;

    char header[3];
    if (!data.read(header, 3)) return false;
    if (header[0] != 'P' || header[1] != 'L' || header[2] != 'R') return false;

    char fmt;
    if (!data.read(&fmt, 1)) return false;
    if (static_cast<int>(fmt) != SAVE_FORMAT) {
        return false;
    }

    char creative;
    if (!data.read(&creative, 1)) return false;
    creative_mode = static_cast<bool>(creative);

    if (!data.read(reinterpret_cast<char*>(&player_health), sizeof(player_health))) return false;

    uint16_t size = 0;
    if (!data.read(reinterpret_cast<char*>(&size), sizeof(size))) return false;

    std::vector<uint8_t> temp;
    if (size > 0) {
        temp.resize(size);
        if (!data.read(reinterpret_cast<char*>(temp.data()), size)) return false;
    }

    // validate expected length: (ITEMS + INVENTORY_SIZE) * 3 bytes
    const size_t expected = (static_cast<size_t>(ITEMS) + static_cast<size_t>(INVENTORY_SIZE)) * 3;
    if (size != expected) {
        // if older/newer formats may differ, handle gracefully; here we reject mismatch
        return false;
    }

    // parse into hotbar and inventory
    size_t idx = 0;
    for (int i = 0; i < ITEMS; ++i) {
        uint8_t numid = temp[idx++];
        uint8_t damage = temp[idx++];
        uint8_t amount = temp[idx++];
        if (amount == 0) {
            hotbar[i].item = nullptr;
        } else {
            Item* itemPtr = &registry[static_cast<int>(numid)];
            hotbar[i].item = itemPtr;
        }
        hotbar[i].damage = damage;
        hotbar[i].amount = amount;
    }

    for (int i = 0; i < INVENTORY_SIZE; ++i) {
        uint8_t numid = temp[idx++];
        uint8_t damage = temp[idx++];
        uint8_t amount = temp[idx++];
        if (amount == 0) {
            inventory[i].item = nullptr;
        } else {
            Item* itemPtr = &registry[static_cast<int>(numid)];
            inventory[i].item = itemPtr;
        }
        inventory[i].damage = damage;
        inventory[i].amount = amount;
    }

    return true;
}
