/**
 * Galaxy Strike Online — Resource System
 * GDD §5: Metal, Gas, Crystal, Energy Cells, Dark Matter
 * Handles production formulas, storage caps, and economy tick integration.
 */

const RESOURCE_TYPES = ['metal', 'gas', 'crystal', 'energyCells', 'darkMatter'];

// GDD §5.1 base rates & storage
const RESOURCE_CONFIG = {
  metal:       { baseRate: 100,  storageBase: 10000, icon: '⚙',  color: '#9e9e9e', label: 'Metal'        },
  gas:         { baseRate: 60,   storageBase: 5000,  icon: '☁',  color: '#4fc3f7', label: 'Gas'          },
  crystal:     { baseRate: 40,   storageBase: 5000,  icon: '💎', color: '#ce93d8', label: 'Crystal'      },
  energyCells: { baseRate: 200,  storageBase: 8000,  icon: '⚡', color: '#fff176', label: 'Energy Cells' },
  darkMatter:  { baseRate: 5,    storageBase: 500,   icon: '✦',  color: '#b39ddb', label: 'Dark Matter'  },
};

// Building → resource production mapping (GDD §5.2, §6.2)
const BUILDING_PRODUCTION = {
  mining_facility:  { metal:      { base: 100, perLevel: 0.15 } },
  gas_extractor:    { gas:        { base: 60,  perLevel: 0.15 } },
  crystal_refinery: { crystal:    { base: 40,  perLevel: 0.12 } },
  power_reactor:    { energyCells:{ base: 200, perLevel: 0.20 } },
  // Dark matter only from endgame structures
};

// Building → storage bonus
const BUILDING_STORAGE = {
  storage_depot: { all: 2000 },
  command_center:{ all: 500  },
};

class ResourceSystem {
  constructor() {
    this.tickIntervalMs = 60000; // 60-second economy tick per GDD §18.2
  }

  /** Initialise resources for a new player */
  initResources(playerData) {
    if (playerData.resources) return; // already initialised
    playerData.resources = {
      metal:       500,
      gas:         200,
      crystal:     100,
      energyCells: 300,
      darkMatter:  0,
      lastTick:    Date.now(),
    };
  }

  /**
   * Calculate per-hour production rates from buildings.
   * GDD formula: output = base_rate × (1 + 0.15 × level) × research_mult × sector_richness
   */
  getProductionRates(playerData) {
    const buildings = playerData.buildings || {};
    const research  = playerData.research?.effects || {};
    const rates     = { metal: 0, gas: 0, crystal: 0, energyCells: 0, darkMatter: 0 };

    for (const [buildId, prod] of Object.entries(BUILDING_PRODUCTION)) {
      const bld = buildings[buildId];
      if (!bld || bld.level < 1) continue;
      for (const [res, cfg] of Object.entries(prod)) {
        const researchMult = 1 + ((research[`${res}Bonus`] || research['miningBonus'] || 0) / 100);
        rates[res] += Math.floor(cfg.base * (1 + cfg.perLevel * bld.level) * researchMult);
      }
    }
    return rates;
  }

  /** Calculate storage caps */
  getStorageCaps(playerData) {
    const buildings = playerData.buildings || {};
    const caps      = {};
    for (const [res, cfg] of Object.entries(RESOURCE_CONFIG)) {
      let cap = cfg.storageBase;
      for (const [buildId, bonus] of Object.entries(BUILDING_STORAGE)) {
        const bld = buildings[buildId];
        if (!bld || bld.level < 1) continue;
        if (bonus.all) cap += bonus.all * bld.level;
        if (bonus[res]) cap += bonus[res] * bld.level;
      }
      caps[res] = cap;
    }
    return caps;
  }

  /**
   * Economy tick — called server-side every 60s.
   * Returns { produced, capped } summary.
   */
  tick(playerData) {
    this.initResources(playerData);
    const now   = Date.now();
    const elapsed = (now - (playerData.resources.lastTick || now)) / 3600000; // hours
    if (elapsed <= 0) return { produced: {}, capped: {} };

    const rates = this.getProductionRates(playerData);
    const caps  = this.getStorageCaps(playerData);
    const res   = playerData.resources;
    const produced = {};
    const capped   = {};

    for (const r of RESOURCE_TYPES) {
      const gain = Math.floor(rates[r] * elapsed);
      if (gain <= 0) continue;
      produced[r] = gain;
      const before = res[r] || 0;
      res[r] = Math.min(before + gain, caps[r]);
      if (res[r] === caps[r] && before + gain > caps[r]) capped[r] = true;
    }
    res.lastTick = now;
    return { produced, capped };
  }

  /** Spend resources — throws if insufficient */
  spend(playerData, costs) {
    this.initResources(playerData);
    const res = playerData.resources;
    for (const [r, amount] of Object.entries(costs)) {
      if ((res[r] || 0) < amount) {
        const label = RESOURCE_CONFIG[r]?.label || r;
        throw new Error(`Insufficient ${label}: need ${amount}, have ${res[r] || 0}`);
      }
    }
    for (const [r, amount] of Object.entries(costs)) {
      res[r] = (res[r] || 0) - amount;
    }
  }

  /** Add resources (from mining, loot, etc.) */
  add(playerData, gains) {
    this.initResources(playerData);
    const caps = this.getStorageCaps(playerData);
    const res  = playerData.resources;
    for (const [r, amount] of Object.entries(gains)) {
      res[r] = Math.min((res[r] || 0) + amount, caps[r] || 999999);
    }
  }

  getConfig()       { return RESOURCE_CONFIG; }
  getTypes()        { return RESOURCE_TYPES; }
  getBuildingProd() { return BUILDING_PRODUCTION; }
}

module.exports = { ResourceSystem, RESOURCE_CONFIG, RESOURCE_TYPES };
