/**
 * InventoryContainer.js
 * Manages a collection of items (stash or bag).
 * Handles stacking logic for consumables and materials.
 */

/**
 * @typedef {Object} ItemInstance
 * @property {string} uid - Unique Instance ID
 * @property {string} defId - Reference to static registry
 * @property {boolean} isNew - For UI "New!" badges
 * @property {number} quantity - For stackables (Potions/Materials)
 */

export class InventoryContainer {
  /**
   * @param {string} id - Container identifier (e.g., "RUN_LOOT" or "HUB_VAULT")
   */
  constructor(id) {
    /** @type {string} */
    this.id = id;

    /** @type {ItemInstance[]} */
    this.items = [];

    /** @type {Object} */
    this.currency = {
      aetherShards: 0,
      ancientCores: 0,
    };
  }

  /**
   * Determines if an item type is stackable.
   * @param {string} defId - Item definition ID
   * @returns {boolean}
   * @private
   */
  _isStackable(defId) {
    // For now, we'll check if the defId suggests it's a consumable or material
    // In a full implementation, this would check the Item Registry
    const stackableTypes = ["CONSUMABLE", "MATERIAL"];
    const lowerDefId = defId.toLowerCase();

    // Check if defId contains keywords that suggest stackability
    return (
      stackableTypes.some((type) => lowerDefId.includes(type.toLowerCase())) ||
      lowerDefId.includes("potion") ||
      lowerDefId.includes("material") ||
      lowerDefId.includes("core") ||
      lowerDefId.includes("shard")
    );
  }

  /**
   * Adds an item to the container.
   * Handles stacking for consumables/materials.
   * @param {ItemInstance} item - Item instance to add
   */
  addItem(item) {
    if (!item || !item.uid || !item.defId) {
      console.warn("Invalid item provided to addItem");
      return;
    }

    // Check if item is stackable
    if (this._isStackable(item.defId)) {
      // Find existing stack with same defId
      const existingStack = this.items.find(
        (i) => i.defId === item.defId && i.quantity < 99
      );

      if (existingStack) {
        // Add to existing stack
        const totalQuantity = existingStack.quantity + item.quantity;
        if (totalQuantity <= 99) {
          existingStack.quantity = totalQuantity;
          // Mark as new if the added item was new
          if (item.isNew) {
            existingStack.isNew = true;
          }
        } else {
          // Cap at 99, create new stack with remainder
          existingStack.quantity = 99;
          const remainder = totalQuantity - 99;
          if (remainder > 0) {
            this.items.push({
              uid: item.uid,
              defId: item.defId,
              isNew: item.isNew,
              quantity: remainder,
            });
          }
        }
      } else {
        // Create new stack
        this.items.push({
          uid: item.uid,
          defId: item.defId,
          isNew: item.isNew,
          quantity: Math.min(item.quantity, 99),
        });

        // If quantity exceeds 99, create additional stacks
        if (item.quantity > 99) {
          let remaining = item.quantity - 99;
          while (remaining > 0) {
            const stackQuantity = Math.min(remaining, 99);
            this.items.push({
              uid: `${item.uid}_${this.items.length}`,
              defId: item.defId,
              isNew: item.isNew,
              quantity: stackQuantity,
            });
            remaining -= stackQuantity;
          }
        }
      }
    } else {
      // Non-stackable items (equipment)
      this.items.push({
        uid: item.uid,
        defId: item.defId,
        isNew: item.isNew,
        quantity: 1, // Equipment always has quantity 1
      });
    }
  }

  /**
   * Removes an item by its unique ID.
   * @param {string} uid - Unique item instance ID
   * @returns {ItemInstance | null} - The removed item, or null if not found
   */
  removeItem(uid) {
    const index = this.items.findIndex((item) => item.uid === uid);
    if (index === -1) {
      return null;
    }

    const removed = this.items.splice(index, 1)[0];
    return removed;
  }

  /**
   * Checks if an item with the given definition ID exists in the container.
   * @param {string} defId - Item definition ID
   * @returns {boolean}
   */
  hasItem(defId) {
    return this.items.some((item) => item.defId === defId);
  }

  /**
   * Finds an item by its unique ID.
   * @param {string} uid - Unique item instance ID
   * @returns {ItemInstance | null}
   */
  findItem(uid) {
    return this.items.find((item) => item.uid === uid) || null;
  }

  /**
   * Returns all items in the container.
   * @returns {ItemInstance[]}
   */
  getAllItems() {
    return [...this.items];
  }

  /**
   * Clears all items from the container.
   */
  clear() {
    this.items = [];
  }
}

