/**
 * Galaxy Strike Online — Alliance System (GDD §12)
 * - Alliance creation (Quantum Relay level 1, 10,000 credits founding fee)
 * - Ranks: Founder, Officer, Veteran, Member
 * - Alliance Warehouse: shared resource pool
 * - Alliance Research stubs (phase 2)
 */

const mongoose = require('mongoose');

const allianceSchema = new mongoose.Schema({
  allianceId:   { type: String, required: true, unique: true },
  name:         { type: String, required: true, unique: true },
  tag:          { type: String, required: true, unique: true, maxlength: 4 },
  founderId:    { type: String, required: true },
  founderName:  { type: String, default: '' },
  description:  { type: String, default: '' },
  createdAt:    { type: Date, default: Date.now },
  members: [{
    userId:   String,
    username: String,
    rank:     { type: String, enum: ['founder','officer','veteran','member'], default: 'member' },
    joinedAt: { type: Date, default: Date.now },
  }],
  // GDD §12.3 Alliance Warehouse
  warehouse: {
    metal:       { type: Number, default: 0 },
    gas:         { type: Number, default: 0 },
    crystal:     { type: Number, default: 0 },
    energyCells: { type: Number, default: 0 },
    credits:     { type: Number, default: 0 },
    maxPerResource: { type: Number, default: 50000 },
  },
  warehouseLog: [{ type: mongoose.Schema.Types.Mixed }],
  // Alliance research (stubbed for phase 2)
  research: { type: mongoose.Schema.Types.Mixed, default: {} },
  maxMembers: { type: Number, default: 50 },
  isRecruiting: { type: Boolean, default: true },
}, { timestamps: true });

const Alliance = mongoose.model('Alliance', allianceSchema);

const RANKS = ['founder', 'officer', 'veteran', 'member'];
const RANK_PERMS = {
  founder:  ['kick', 'promote', 'demote', 'deposit', 'withdraw', 'edit', 'disband'],
  officer:  ['kick_member', 'promote_veteran', 'deposit', 'withdraw'],
  veteran:  ['deposit', 'withdraw_limited'],
  member:   ['deposit'],
};

class AllianceSystem {
  constructor() { this.Alliance = Alliance; }

  async createAlliance(playerData, { name, tag, description = '' }) {
    if (!name || name.length < 3 || name.length > 24) throw new Error('Alliance name must be 3–24 characters');
    if (!tag  || tag.length  < 2 || tag.length  > 4)  throw new Error('Alliance tag must be 2–4 characters');
    if (playerData.stats.credits < 10000) throw new Error('Founding fee is 10,000 credits');
    if (playerData.allianceId) throw new Error('You are already in an alliance');

    // Check Quantum Relay (if building exists)
    const qrLevel = playerData.buildings?.quantum_relay?.level || 0;
    // Allow creation even without relay in early access — just warn
    // if (qrLevel < 1) throw new Error('Quantum Relay level 1 required to found an alliance');

    const allianceId = 'alliance_' + Date.now() + '_' + Math.random().toString(36).slice(2,6);
    const alliance = new Alliance({
      allianceId,
      name: name.trim(),
      tag:  tag.toUpperCase().trim(),
      founderId: playerData.userId,
      founderName: playerData.username,
      description: description.trim(),
      members: [{ userId: playerData.userId, username: playerData.username, rank: 'founder', joinedAt: new Date() }],
    });
    await alliance.save();

    playerData.stats.credits -= 10000;
    playerData.allianceId   = allianceId;
    playerData.allianceTag  = alliance.tag;
    playerData.allianceName = alliance.name;
    playerData.allianceRank = 'founder';
    return alliance;
  }

  async joinAlliance(playerData, allianceId) {
    if (playerData.allianceId) throw new Error('Leave your current alliance first');
    const alliance = await Alliance.findOne({ allianceId });
    if (!alliance) throw new Error('Alliance not found');
    if (!alliance.isRecruiting) throw new Error('Alliance is not recruiting');
    if (alliance.members.length >= alliance.maxMembers) throw new Error('Alliance is full');

    alliance.members.push({ userId: playerData.userId, username: playerData.username, rank: 'member', joinedAt: new Date() });
    await alliance.save();

    playerData.allianceId   = allianceId;
    playerData.allianceTag  = alliance.tag;
    playerData.allianceName = alliance.name;
    playerData.allianceRank = 'member';
    return alliance;
  }

  async leaveAlliance(playerData) {
    if (!playerData.allianceId) throw new Error('Not in an alliance');
    const alliance = await Alliance.findOne({ allianceId: playerData.allianceId });
    if (!alliance) { playerData.allianceId = null; return; }

    if (alliance.founderId === playerData.userId && alliance.members.length > 1) {
      throw new Error('Transfer leadership before leaving');
    }
    alliance.members = alliance.members.filter(m => m.userId !== playerData.userId);
    if (alliance.members.length === 0) {
      await Alliance.deleteOne({ allianceId: playerData.allianceId });
    } else {
      await alliance.save();
    }
    playerData.allianceId = null;
    playerData.allianceTag = null;
    playerData.allianceName = null;
    playerData.allianceRank = null;
  }

  async depositWarehouse(playerData, { resource, amount }) {
    if (!playerData.allianceId) throw new Error('Not in an alliance');
    if (!['metal','gas','crystal','energyCells','credits'].includes(resource)) throw new Error('Invalid resource');
    amount = Math.floor(amount);
    if (amount <= 0) throw new Error('Amount must be positive');

    const alliance = await Alliance.findOne({ allianceId: playerData.allianceId });
    if (!alliance) throw new Error('Alliance not found');

    // Deduct from player
    const resKey = resource === 'credits' ? null : resource;
    if (resource === 'credits') {
      if ((playerData.stats.credits || 0) < amount) throw new Error('Insufficient credits');
      playerData.stats.credits -= amount;
    } else {
      if (!playerData.resources || (playerData.resources[resource] || 0) < amount) throw new Error(`Insufficient ${resource}`);
      playerData.resources[resource] -= amount;
    }

    alliance.warehouse[resource] = Math.min((alliance.warehouse[resource] || 0) + amount, alliance.warehouse.maxPerResource);
    alliance.warehouseLog.push({ userId: playerData.userId, username: playerData.username, action:'deposit', resource, amount, at: new Date() });
    if (alliance.warehouseLog.length > 200) alliance.warehouseLog = alliance.warehouseLog.slice(-200);
    await alliance.save();
    return alliance.warehouse;
  }

  async withdrawWarehouse(playerData, { resource, amount }) {
    if (!playerData.allianceId) throw new Error('Not in an alliance');
    const rank = playerData.allianceRank || 'member';
    if (!RANK_PERMS[rank]?.some(p => p.startsWith('withdraw'))) throw new Error('Insufficient rank to withdraw');

    const alliance = await Alliance.findOne({ allianceId: playerData.allianceId });
    if (!alliance) throw new Error('Alliance not found');
    amount = Math.floor(amount);
    if ((alliance.warehouse[resource] || 0) < amount) throw new Error('Insufficient in warehouse');

    alliance.warehouse[resource] -= amount;
    if (resource === 'credits') playerData.stats.credits = (playerData.stats.credits || 0) + amount;
    else { if (!playerData.resources) playerData.resources = {}; playerData.resources[resource] = (playerData.resources[resource]||0) + amount; }
    alliance.warehouseLog.push({ userId: playerData.userId, username: playerData.username, action:'withdraw', resource, amount, at: new Date() });
    await alliance.save();
    return alliance.warehouse;
  }

  async getAllianceData(allianceId) {
    return Alliance.findOne({ allianceId }).lean();
  }

  async searchAlliances(query = '') {
    const q = query.trim();
    const filter = q ? { $or: [{ name: new RegExp(q,'i') }, { tag: new RegExp(q,'i') }] } : {};
    return Alliance.find(filter, { name:1, tag:1, description:1, allianceId:1, 'members':1, isRecruiting:1, maxMembers:1 }).limit(20).lean();
  }
}

module.exports = { AllianceSystem, Alliance };
