// zig fmt: off
const std = @import("std");
const json_utils = @import("../json_utils.zig");
const Store = @import("../store.zig");
const Item = @import("./item.zig");
const EnumStringUtils = @import("../enum_string_utils.zig").EnumStringUtils;

const Equipment = @This();

pub const Slot = struct {
    item: ?Store.Id = null,
    quantity: u64 = 0,

    fn parse(store: *Store, obj: std.json.ObjectMap, name: []const u8) !Slot {
        const item_code = try json_utils.getStringRequired(obj, name);
        if (item_code.len == 0) {
            return Slot{};
        }

        return Slot{
            .item = try store.items.getOrReserveId(item_code),
            .quantity = 1
        };
    }

    fn parseWithQuantity(store: *Store, obj: std.json.ObjectMap, name: []const u8, quantity: []const u8) !Slot {
        var slot = try Slot.parse(store, obj, name);
        if (slot.item != null) {
            slot.quantity = try json_utils.getPositiveIntegerRequired(obj, quantity);
        }

        return slot;
    }
};

pub const SlotId = enum {
    weapon,
    shield,
    helmet,
    body_armor,
    leg_armor,
    boots,
    ring1,
    ring2,
    amulet,
    artifact1,
    artifact2,
    artifact3,
    utility1,
    utility2,

    const Utils = EnumStringUtils(SlotId, .{
        .{ "weapon"    , SlotId.weapon     },
        .{ "shield"    , SlotId.shield     },
        .{ "helmet"    , SlotId.helmet     },
        .{ "body_armor", SlotId.body_armor },
        .{ "leg_armor" , SlotId.leg_armor  },
        .{ "boots"     , SlotId.boots      },
        .{ "ring1"     , SlotId.ring1      },
        .{ "ring2"     , SlotId.ring2      },
        .{ "amulet"    , SlotId.amulet     },
        .{ "artifact1" , SlotId.artifact1  },
        .{ "artifact2" , SlotId.artifact2  },
        .{ "artifact3" , SlotId.artifact3  },
        .{ "utility1"  , SlotId.utility1   },
        .{ "utility2"  , SlotId.utility2   },
    });

    pub const toString = Utils.toString;
    pub const fromString = Utils.fromString;

    pub fn canHoldManyItems(self: SlotId) bool {
        return self == .utility1 or self == .utility2;
    }
};

pub const Slots = std.EnumArray(SlotId, Slot);

slots: Slots,

pub fn parse(store: *Store, obj: std.json.ObjectMap) !Equipment {
    return Equipment{
        .slots = Slots.init(.{
            .weapon     = try Slot.parse(store, obj, "weapon_slot"),
            .shield     = try Slot.parse(store, obj, "shield_slot"),
            .helmet     = try Slot.parse(store, obj, "helmet_slot"),
            .body_armor = try Slot.parse(store, obj, "body_armor_slot"),
            .leg_armor  = try Slot.parse(store, obj, "leg_armor_slot"),
            .boots      = try Slot.parse(store, obj, "boots_slot"),
            .ring1      = try Slot.parse(store, obj, "ring1_slot"),
            .ring2      = try Slot.parse(store, obj, "ring2_slot"),
            .amulet     = try Slot.parse(store, obj, "amulet_slot"),
            .artifact1  = try Slot.parse(store, obj, "artifact1_slot"),
            .artifact2  = try Slot.parse(store, obj, "artifact2_slot"),
            .artifact3  = try Slot.parse(store, obj, "artifact3_slot"),
            .utility1   = try Slot.parseWithQuantity(store, obj, "utility1_slot", "utility1_slot_quantity"),
            .utility2   = try Slot.parseWithQuantity(store, obj, "utility2_slot", "utility2_slot_quantity"),
        })
    };
}
