#include "models/crafting.h"

typedef struct {
    uint8_t selected_item;
    bool drop_item;
    
    bool item_is_held;
    uint8_t held_item_idx;
    Item held_item;
    
    bool is_inside;
    bool storage_action;
    bool swap;
    uint8_t swap_from;
    uint8_t swap_to;
    uint16_t craft_item;
} inv_keystate;

static inv_keystate player_inv = {0};
static inv_keystate storage_inv = {0};

bool inv_is_open = false;
bool inv_is_inside = false;
bool inv_is_storage_action = false;
bool inv_swap_storage = false;

// TODO(zaklaus): 
// TODO(zaklaus): MOVE TO COMMON UI MODULE
// TODO(zaklaus): 

typedef struct {
    float x, y;
} inv_draw_result;

static inline
int UIMeasureText(const char *text, int fontSize) {
    Vector2 vec = { 0.0f, 0.0f };
    
    // Check if default font has been loaded
    if (GetFontDefault().texture.id != 0) {
        int defaultFontSize = 10;   // Default Font chars height in pixel
        int new_spacing = fontSize/defaultFontSize;
        
        vec = MeasureTextEx(GetFontDefault(), text, (float)fontSize, (float)new_spacing);
    }
    
    return (int)vec.x;
}

static inline
void UIDrawText(const char *text, float posX, float posY, int fontSize, Color color) {
    // Check if default font has been loaded
    if (GetFontDefault().texture.id != 0) {
        Vector2 position = { (float)posX , (float)posY  };
        
        int defaultFontSize = 22;   // Default Font chars height in pixel
        int new_spacing = fontSize/defaultFontSize;
        
        DrawTextEx(GetFontDefault(), text, position, (float)fontSize , (float)new_spacing , color);
    }
}


static inline inv_draw_result
DrawColoredText(float xpos, float ypos, char const *text, Color color) {
    ZPL_ASSERT(text);
    UIDrawText(text, xpos, ypos, 22, color);
    
    char const *p = text;
    uint8_t newlines = 1;
    
    do {
        if (*p == '\n')
            ++newlines;
    } while (*p++ != 0);
    
    return (inv_draw_result){.x = xpos + UIMeasureText(text, 22), .y = ypos + 22*newlines};
}


static inline
inv_draw_result inventory_draw_crafting_btn(float xpos, float ypos, const char *name, uint16_t id, Color color) {
    float name_width=0.0f;
    char const *text = TextFormat("> %s", name);
    name_width = (float)UIMeasureText(text, 22);
    
    Color new_color = color;
    if (is_btn_pressed(xpos, ypos, name_width, 22, &new_color)) {
        inv_is_inside = true;
        player_inv.craft_item = id;
    }

	if (check_mouse_area(xpos, ypos, name_width, 22) != DAREA_OUTSIDE) {
		Vector2 mpos = GetMousePosition();
		recipe rp = craft_get_recipe_data(craft_get_recipe_id_from_product(id));
		if (nk_begin(game_ui , name, nk_rect(mpos.x+15, mpos.y+15, name_width+5, 1200),
		             NK_WINDOW_BORDER | NK_WINDOW_NO_INPUT | NK_WINDOW_NO_SCROLLBAR | NK_WINDOW_DYNAMIC)) {
			if (nk_tree_push_id(game_ui, NK_TREE_NODE, "Overview", NK_MAXIMIZED, id)) {
				{
					tooltip_draw_contents(tooltip_find_desc(name));
				}
				nk_tree_pop(game_ui);
			}
			if (nk_tree_push_id(game_ui, NK_TREE_NODE, "Reagents", NK_MAXIMIZED, id)) {
				for (asset_id i = 0; rp.reagents[i].id; i++) {
					nk_label(game_ui, asset_names[rp.reagents[i].id], NK_TEXT_LEFT);
				}
				nk_tree_pop(game_ui);
			}
			nk_end(game_ui);
		}
	}
    
    Color _c_compare_lol = BLACK;
    if (!zpl_memcompare(&color, &_c_compare_lol, sizeof(Color))) {
        new_color = BLACK;
    }
    
    inv_draw_result res = DrawColoredText(xpos, ypos, text, new_color);
    ypos = res.y;

    return res;
}

static inline
bool inventory_draw_crafting_list(entity_view *e, float xpos, float ypos) {
    float start_xpos = xpos;
    float start_ypos = ypos;

    for (uint16_t i = 0; e->craftables[i]; ++i) {
		asset_id id = e->craftables[i];
        inventory_draw_crafting_btn(start_xpos+1, ypos+1, asset_names[id], id, BLACK);
        inv_draw_result entry = inventory_draw_crafting_btn(start_xpos, ypos, asset_names[id], id, RAYWHITE);
        ypos = entry.y;
        xpos = zpl_max(xpos, entry.x);
    }
    
    return check_mouse_area(start_xpos, start_ypos, xpos-start_xpos, ypos-start_ypos) != DAREA_OUTSIDE;
}

void inventory_draw_panel(entity_view *e, bool is_player, float sx, float sy){
    if (!e->has_items && is_player)
        return;
    if (!e->has_storage_items && !is_player)
        return;
    
    float x = sx;
    float y = sy;
    
    const int32_t grid_size = (is_player) ? (64*3) : (64*4);
    const int32_t inv_size = (is_player) ? ITEMS_INVENTORY_SIZE : ITEMS_CONTAINER_SIZE;
    const int32_t inv_cols = (is_player) ? 3 : 4;
    
    inv_keystate *inv = (!is_player) ? &storage_inv : &player_inv;
    inv_keystate *inv2 = (is_player) ? &storage_inv : &player_inv;
    
    bool inside_craft = !is_player && inventory_draw_crafting_list(e, screenWidth/2.0f - 684, screenHeight/2.0f - 128);
    
    inv->is_inside = check_mouse_area(sx, sy, (float)grid_size, (float)grid_size) != DAREA_OUTSIDE;
    inv_is_inside |= inv->is_inside || inside_craft;
    
    for (int32_t i = 0; i < inv_size; i += 1) {
        {
            debug_area_status area = check_mouse_area(x, y, 64, 64);
            Color color = RAYWHITE;
            Item *item = (is_player) ? &e->items[i] : &e->storage_items[i];
            
            if (area == DAREA_HOVER) {
                color = YELLOW;
            } else if (area == DAREA_PRESS && inv2->item_is_held){
                color = VIOLET;
                inv_swap_storage = true;
                inv_is_storage_action = true;
                inv->item_is_held = false;
                inv2->item_is_held = false;
                inv->selected_item = i;
                inv->swap = true;
                inv->swap_from = inv2->held_item_idx;
                inv->swap_to = i;
            } else if (area == DAREA_PRESS && !inv->item_is_held && !inv2->item_is_held) {
                color = VIOLET;
                inv_is_storage_action = true;
                inv->selected_item = i;
            } else if (area == DAREA_PRESS && inv->item_is_held) {
                color = VIOLET;
                inv_is_storage_action = true;
                inv->selected_item = i;
                inv->item_is_held = false;
                inv->swap = true;
                inv->swap_from = inv->held_item_idx;
                inv->swap_to = i;
            } else if (area == DAREA_HELD && item->quantity > 0 && !inv->item_is_held && !inv2->item_is_held) {
                inv_is_storage_action = true;
                inv->selected_item = i;
                inv->item_is_held = true;
                inv->held_item = *item;
                inv->held_item_idx = i;
            } else if (i == inv->selected_item) {
                color = RED;
            }
            
            DrawRectangleLinesEco(x, y, 64, 64, color);
            
            if (item->quantity > 0) {
                Texture2D tex = GetSpriteTexture2D(assets_find(item->kind));
                float aspect = tex.width/(float)tex.height;
                float size = WORLD_BLOCK_SIZE * aspect;
                float ofs_x = (WORLD_BLOCK_SIZE-size)/2.0f;
                DrawTexturePro(tex, ASSET_SRC_RECT_TEX(tex.width, tex.height), ASSET_DST_RECT_TEX(x+ofs_x, y, size, WORLD_BLOCK_SIZE), (Vector2){0.5f,0.5f}, 0.0f, WHITE);
            }
            
            if (item->quantity > 1) {
                DrawTextEco(zpl_bprintf("%d", item->quantity), x+5, y+5, 16, RAYWHITE, 0.0f);
            }
            
            if (item->quantity > 0 && item->durability < 1.0f) {
                DrawRectangleEco(x, y+56, 64, 8, BLACK);
                DrawRectangleEco(x, y+56, 64*item->durability, 8, BlendColor(RED, GREEN, item->durability));
            }
        }
        x += 64;
        
        if ((i+1) % inv_cols == 0) {
            x = sx;
            y += 64;
        }
    }
    
    // NOTE(zaklaus): switch it off if is_player
    if (is_player)
        inv_is_storage_action = false;
}

void inventory_render_held_item(bool is_player){
    inv_keystate *inv = (!is_player) ? &storage_inv : &player_inv;
    inv_keystate *inv2 = (is_player) ? &storage_inv : &player_inv;
    
    if (inv->item_is_held) {
        Vector2 mpos = GetMousePosition();
        mpos.x -= 32;
        mpos.y -= 32;
        Texture2D tex = GetSpriteTexture2D(assets_find(inv->held_item.kind));
        float aspect = tex.width/(float)tex.height;
        float size = WORLD_BLOCK_SIZE * aspect;
        float ofs_x = (WORLD_BLOCK_SIZE-size)/2.0f;
        DrawTexturePro(tex, ASSET_SRC_RECT_TEX(tex.width, tex.height), ASSET_DST_RECT_TEX(mpos.x+ofs_x, mpos.y, size, WORLD_BLOCK_SIZE), (Vector2){0.5f,0.5f}, 0.0f, ColorAlpha(WHITE, 0.8f));
        DrawTextEco(zpl_bprintf("%d", inv->held_item.quantity), mpos.x, mpos.y, 16, RAYWHITE, 0.0f);
        
        if (!inv->is_inside && IsMouseButtonReleased(MOUSE_LEFT_BUTTON) && !inv2->is_inside) {
            inv->drop_item = true;
            inv->item_is_held = false;
            inv_is_storage_action = inv == &storage_inv;
        }
    }
}

void inventory_reset_states(inv_keystate *ik) {
    ik->drop_item = false;
    ik->swap = false;
    ik->craft_item = 0;
}

void inventory_draw() {
    inv_is_storage_action = false;
    inv_is_inside = false;
    inv_swap_storage = false;
    inventory_reset_states(&player_inv);
    inventory_reset_states(&storage_inv);
    
    camera cam = camera_get();
    entity_view *e = game_world_view_active_get_entity(cam.ent_id);
    if (!e || !e->has_items) return;
    
    if (input_is_pressed(IN_TOGGLE_INV)) {
        inv_is_open = !inv_is_open;
    }
    
    if (!inv_is_open || build_is_in_draw_mode) {
        return;
    }
    
    inventory_draw_panel(e, true, screenWidth/2.0f + 128, screenHeight/2.0f - 96);
    inventory_draw_panel(e, false, screenWidth/2.0f - 384, screenHeight/2.0f - 128);
    
    inventory_render_held_item(true);
    inventory_render_held_item(false);
}
