'use strict';

/**
 * Sistema modular de Comandantes, Governadores e Equipamentos.
 * Inspirado na lógica de RPG do GGE, mas com dados, nomes e ícones originais do Reinos de Ferro.
 */
(() => {
  const VERSION = 3;

  const ROLES = {
    commanders: { singular: 'Comandante', plural: 'Comandantes', short: 'Comandante', icon: '⚔️', activeKey: 'selectedCommanderId', listKey: 'commanders', focus: 'ataque' },
    governors: { singular: 'Governador', plural: 'Governadores', short: 'Governador', icon: '🛡️', activeKey: 'selectedGovernorId', listKey: 'governors', focus: 'defesa' }
  };

  const SLOTS = {
    weapon: { name: 'Arma', icon: '🗡️' },
    helmet: { name: 'Capacete', icon: '⛑️' },
    armor: { name: 'Armadura', icon: '🛡️' },
    artifact: { name: 'Artefacto', icon: '📿' },
    look: { name: 'Visual', icon: '🎖️' },
    hero: { name: 'Herói', icon: '🦁' }
  };

  const SLOT_ORDER = ['weapon', 'helmet', 'armor', 'artifact', 'look', 'hero'];

  const RARITIES = {
    common: { name: 'Comum', color: '#8c8f86', mult: 1.00 },
    rare: { name: 'Raro', color: '#35a852', mult: 1.35 },
    epic: { name: 'Épico', color: '#8a46d9', mult: 1.85 },
    legendary: { name: 'Lendário', color: '#e98720', mult: 2.35 },
    unique: { name: 'Único', color: '#c82028', mult: 2.95 },
    relic: { name: 'Relíquia', color: '#2ba7e8', mult: 3.50 }
  };

  const EQUIPMENT_SETS = {
    falken_baron: {
      name: 'Set do Barão Falken', short: 'Barão Falken', icon: '🦅', color: '#c58d4a',
      description: 'Conjunto equilibrado encontrado nos Barões. Bom para evoluir no início e manter saques constantes.',
      statBias: {
        commanders: ['lootBonus', 'travelSpeed', 'findEquipment', 'meleeAttack', 'rangedAttack'],
        governors: ['wallDefense', 'gateDefense', 'resourceProtection', 'meleeDefense', 'rangedDefense']
      },
      bonuses: {
        commanders: {
          2: { lootBonus: 8, travelSpeed: 4 },
          4: { meleeAttack: 8, rangedAttack: 8, wallReduction: 6 },
          6: { lootBonus: 16, findEquipment: 10, gateReduction: 8 }
        },
        governors: {
          2: { resourceProtection: 8, wallDefense: 5 },
          4: { meleeDefense: 8, rangedDefense: 8, gateDefense: 6 },
          6: { resourceProtection: 16, wallDefense: 12, publicOrder: 30 }
        }
      }
    },
    royal_warrior: {
      name: 'Set do Guerreiro Real', short: 'Guerreiro Real', icon: '👑', color: '#d8b45c',
      description: 'Conjunto de ataque nobre para comandantes focados em força direta.',
      statBias: {
        commanders: ['meleeAttack', 'rangedAttack', 'wallReduction', 'gateReduction'],
        governors: ['meleeDefense', 'rangedDefense', 'gateDefense', 'wallDefense']
      },
      bonuses: {
        commanders: {
          2: { meleeAttack: 10, rangedAttack: 6 },
          4: { meleeAttack: 14, rangedAttack: 14, gateReduction: 8 },
          6: { meleeAttack: 20, rangedAttack: 18, wallReduction: 12 }
        },
        governors: {
          2: { meleeDefense: 8, gateDefense: 4 },
          4: { meleeDefense: 12, rangedDefense: 10, wallDefense: 6 },
          6: { meleeDefense: 18, rangedDefense: 16, gateDefense: 10 }
        }
      }
    },
    fortress_guardian: {
      name: 'Set do Guardião da Fortaleza', short: 'Guardião da Fortaleza', icon: '🏰', color: '#6f91b6',
      description: 'Conjunto defensivo pesado, ideal para governadores e defesa da muralha.',
      statBias: {
        commanders: ['wallReduction', 'gateReduction', 'meleeAttack', 'rangedAttack'],
        governors: ['wallDefense', 'gateDefense', 'meleeDefense', 'rangedDefense', 'resourceProtection']
      },
      bonuses: {
        commanders: {
          2: { wallReduction: 6, gateReduction: 4 },
          4: { meleeAttack: 8, rangedAttack: 8, wallReduction: 10 },
          6: { gateReduction: 14, wallReduction: 14, travelSpeed: 6 }
        },
        governors: {
          2: { wallDefense: 10, gateDefense: 6 },
          4: { meleeDefense: 12, rangedDefense: 12, wallDefense: 14 },
          6: { wallDefense: 22, gateDefense: 18, resourceProtection: 12 }
        }
      }
    },
    raider: {
      name: 'Set do Saqueador', short: 'Saqueador', icon: '💰', color: '#b26b3a',
      description: 'Conjunto rápido para ataques de saque e deslocações frequentes no mapa.',
      statBias: {
        commanders: ['lootBonus', 'travelSpeed', 'wallReduction', 'gateReduction', 'findEquipment'],
        governors: ['resourceProtection', 'gateDefense', 'rangedDefense', 'publicOrder']
      },
      bonuses: {
        commanders: {
          2: { lootBonus: 14, travelSpeed: 5 },
          4: { lootBonus: 24, travelSpeed: 10, gateReduction: 6 },
          6: { lootBonus: 36, travelSpeed: 16, findEquipment: 8 }
        },
        governors: {
          2: { resourceProtection: 10, gateDefense: 4 },
          4: { resourceProtection: 18, rangedDefense: 10, publicOrder: 20 },
          6: { resourceProtection: 28, gateDefense: 12, rangedDefense: 14 }
        }
      }
    },
    stone_defender: {
      name: 'Set do Defensor de Pedra', short: 'Defensor de Pedra', icon: '🪨', color: '#8a969f',
      description: 'Conjunto de resistência para segurar ataques fortes contra o castelo.',
      statBias: {
        commanders: ['meleeAttack', 'rangedAttack', 'gateReduction'],
        governors: ['meleeDefense', 'rangedDefense', 'wallDefense', 'gateDefense']
      },
      bonuses: {
        commanders: {
          2: { meleeAttack: 6, rangedAttack: 6 },
          4: { meleeAttack: 10, rangedAttack: 10, gateReduction: 8 },
          6: { meleeAttack: 14, rangedAttack: 14, wallReduction: 10 }
        },
        governors: {
          2: { meleeDefense: 10, rangedDefense: 8 },
          4: { meleeDefense: 16, rangedDefense: 16, wallDefense: 10 },
          6: { meleeDefense: 24, rangedDefense: 22, gateDefense: 16 }
        }
      }
    },
    imperial_relic: {
      name: 'Set Relíquia Imperial', short: 'Relíquia Imperial', icon: '💎', color: '#36b7ee',
      description: 'Conjunto raro e poderoso para jogadores avançados.',
      statBias: {
        commanders: ['meleeAttack', 'rangedAttack', 'travelSpeed', 'lootBonus', 'wallReduction', 'gateReduction'],
        governors: ['meleeDefense', 'rangedDefense', 'wallDefense', 'gateDefense', 'resourceProtection', 'publicOrder']
      },
      bonuses: {
        commanders: {
          2: { meleeAttack: 12, rangedAttack: 12, travelSpeed: 5 },
          4: { meleeAttack: 20, rangedAttack: 20, wallReduction: 12, gateReduction: 12 },
          6: { meleeAttack: 30, rangedAttack: 30, travelSpeed: 14, lootBonus: 20, findEquipment: 12 }
        },
        governors: {
          2: { meleeDefense: 12, rangedDefense: 12, wallDefense: 6 },
          4: { meleeDefense: 20, rangedDefense: 20, wallDefense: 14, gateDefense: 14 },
          6: { meleeDefense: 30, rangedDefense: 30, wallDefense: 20, gateDefense: 20, publicOrder: 60 }
        }
      }
    }
  };

  const SET_ORDER = ['falken_baron', 'royal_warrior', 'fortress_guardian', 'raider', 'stone_defender', 'imperial_relic'];

  const STAT_META = {
    meleeAttack: { label: 'Ataque corpo a corpo', suffix: '%', role: 'commanders' },
    rangedAttack: { label: 'Ataque à distância', suffix: '%', role: 'commanders' },
    wallReduction: { label: 'Redução de muralha inimiga', suffix: '%', role: 'commanders' },
    gateReduction: { label: 'Redução de portão inimigo', suffix: '%', role: 'commanders' },
    travelSpeed: { label: 'Velocidade de viagem', suffix: '%', role: 'commanders' },
    lootBonus: { label: 'Saque obtido', suffix: '%', role: 'commanders' },
    findEquipment: { label: 'Chance de encontrar equipamento', suffix: '%', role: 'commanders' },

    meleeDefense: { label: 'Defesa corpo a corpo', suffix: '%', role: 'governors' },
    rangedDefense: { label: 'Defesa à distância', suffix: '%', role: 'governors' },
    wallDefense: { label: 'Bónus de muralha', suffix: '%', role: 'governors' },
    gateDefense: { label: 'Bónus de portão', suffix: '%', role: 'governors' },
    resourceProtection: { label: 'Proteção de recursos', suffix: '%', role: 'governors' },
    publicOrder: { label: 'Ordem pública', suffix: '', role: 'governors' }
  };

  const COMMANDER_STAT_POOL = ['meleeAttack', 'rangedAttack', 'wallReduction', 'gateReduction', 'travelSpeed', 'lootBonus', 'findEquipment'];
  const GOVERNOR_STAT_POOL = ['meleeDefense', 'rangedDefense', 'wallDefense', 'gateDefense', 'resourceProtection', 'publicOrder'];

  const ITEM_WORDS = {
    weapon: ['Espada', 'Machado', 'Lança', 'Sabre'],
    helmet: ['Elmo', 'Capacete', 'Coroa de guerra', 'Barbuta'],
    armor: ['Cota', 'Couraça', 'Armadura', 'Peitoral'],
    artifact: ['Amuleto', 'Selo', 'Relicário', 'Insígnia'],
    look: ['Estandarte', 'Capa', 'Insígnia real', 'Pele de campanha'],
    hero: ['Campeão', 'Capitão', 'Guardião', 'Arauto']
  };

  function number(value, fallback = 0) {
    return Number.isFinite(Number(value)) ? Number(value) : fallback;
  }

  function clamp(value, min, max) {
    return Math.max(min, Math.min(max, value));
  }

  function escapeHtml(text) {
    return String(text ?? '').replace(/[&<>'"]/g, char => ({ '&': '&amp;', '<': '&lt;', '>': '&gt;', "'": '&#039;', '"': '&quot;' }[char]));
  }

  function uid(prefix = 'eq') {
    return `${prefix}_${Date.now().toString(36)}_${Math.random().toString(36).slice(2, 9)}`;
  }

  function emptySlots() {
    return Object.fromEntries(SLOT_ORDER.map(slot => [slot, null]));
  }

  function createCharacters(role) {
    if (role === 'commanders') {
      return [
        { id: uid('cmd'), name: 'Comandante I', level: 1, xp: 0, slots: emptySlots() },
        { id: uid('cmd'), name: 'Comandante II', level: 1, xp: 0, slots: emptySlots() },
        { id: uid('cmd'), name: 'Comandante III', level: 1, xp: 0, slots: emptySlots() }
      ];
    }
    return [
      { id: uid('gov'), name: 'Governador do Castelo', level: 1, xp: 0, slots: emptySlots() }
    ];
  }

  function ensureState(profile) {
    if (!profile) return null;
    if (!profile.equipment || typeof profile.equipment !== 'object') profile.equipment = {};
    const state = profile.equipment;
    if (state.version !== VERSION) state.version = VERSION;
    if (!Array.isArray(state.inventory)) state.inventory = [];
    if (!Array.isArray(state.commanders) || !state.commanders.length) state.commanders = createCharacters('commanders');
    if (!Array.isArray(state.governors) || !state.governors.length) state.governors = createCharacters('governors');
    state.commanders.forEach((character, index) => {
      character.id = character.id || uid('cmd');
      character.name = character.name || `Comandante ${index + 1}`;
      character.level = Math.max(1, Math.floor(number(character.level, 1)));
      character.slots = { ...emptySlots(), ...(character.slots || {}) };
    });
    state.governors.forEach((character, index) => {
      character.id = character.id || uid('gov');
      character.name = character.name || (index ? `Governador ${index + 1}` : 'Governador do Castelo');
      character.level = Math.max(1, Math.floor(number(character.level, 1)));
      character.slots = { ...emptySlots(), ...(character.slots || {}) };
    });
    if (!state.selectedCommanderId || !state.commanders.some(item => item.id === state.selectedCommanderId)) state.selectedCommanderId = state.commanders[0]?.id || null;
    if (!state.selectedGovernorId || !state.governors.some(item => item.id === state.selectedGovernorId)) state.selectedGovernorId = state.governors[0]?.id || null;
    state.inventory.forEach(item => normalizeItem(item));
    return state;
  }

  function normalizeItem(item) {
    item.id = item.id || uid('eq');
    item.role = item.role === 'governors' ? 'governors' : 'commanders';
    item.slot = SLOTS[item.slot] ? item.slot : 'artifact';
    item.rarity = RARITIES[item.rarity] ? item.rarity : 'common';
    item.setId = EQUIPMENT_SETS[item.setId] ? item.setId : null;
    item.level = Math.max(1, Math.floor(number(item.level, 1)));
    item.stats = item.stats && typeof item.stats === 'object' ? item.stats : {};
    item.name = item.name || buildItemName(item);
    item.icon = item.icon || SLOTS[item.slot]?.icon || '◆';
    return item;
  }

  function findItem(profile, itemId) {
    return ensureState(profile)?.inventory.find(item => item.id === itemId) || null;
  }

  function roleDef(role) {
    return ROLES[role] || ROLES.commanders;
  }

  function selectedCharacter(state, role) {
    const def = roleDef(role);
    const list = state?.[def.listKey] || [];
    return list.find(character => character.id === state?.[def.activeKey]) || list[0] || null;
  }

  function itemEquippedBy(state, itemId) {
    for (const role of Object.keys(ROLES)) {
      for (const character of state?.[ROLES[role].listKey] || []) {
        for (const slot of SLOT_ORDER) {
          if (character.slots?.[slot] === itemId) return { role, character, slot };
        }
      }
    }
    return null;
  }

  function equippedItems(profile, character) {
    const state = ensureState(profile);
    return SLOT_ORDER.map(slot => findItemById(state, character?.slots?.[slot])).filter(Boolean);
  }

  function findItemById(state, id) {
    return state?.inventory?.find(item => item.id === id) || null;
  }

  function characterRole(profile, character) {
    const state = ensureState(profile);
    if (state?.governors?.some(item => item.id === character?.id)) return 'governors';
    return 'commanders';
  }

  function addStatsInto(target, stats) {
    Object.entries(stats || {}).forEach(([stat, value]) => {
      target[stat] = (target[stat] || 0) + number(value, 0);
    });
    return target;
  }

  function setCounts(profile, character) {
    const counts = {};
    equippedItems(profile, character).forEach(item => {
      if (!item.setId || !EQUIPMENT_SETS[item.setId]) return;
      counts[item.setId] = (counts[item.setId] || 0) + 1;
    });
    return counts;
  }

  function setBonusStats(profile, character, role = null) {
    const activeRole = role || characterRole(profile, character);
    const counts = setCounts(profile, character);
    const totals = {};
    Object.entries(counts).forEach(([setId, count]) => {
      const set = EQUIPMENT_SETS[setId];
      [2, 4, 6].forEach(threshold => {
        if (count >= threshold) addStatsInto(totals, set?.bonuses?.[activeRole]?.[threshold]);
      });
    });
    return totals;
  }

  function characterBonuses(profile, character) {
    const totals = {};
    equippedItems(profile, character).forEach(item => addStatsInto(totals, item.stats));
    addStatsInto(totals, setBonusStats(profile, character));
    return totals;
  }

  function activeCommander(profile) {
    const state = ensureState(profile);
    return selectedCharacter(state, 'commanders');
  }

  function activeGovernor(profile) {
    const state = ensureState(profile);
    return selectedCharacter(state, 'governors');
  }

  function commanderBonuses(profile, mission = null) {
    const state = ensureState(profile);
    let character = null;
    if (mission?.commanderId) character = state.commanders.find(item => item.id === mission.commanderId) || null;
    if (!character) character = activeCommander(profile);
    return characterBonuses(profile, character);
  }

  function governorBonuses(profile) {
    return characterBonuses(profile, activeGovernor(profile));
  }

  function sumItemPower(item) {
    return Object.values(item?.stats || {}).reduce((sum, value) => sum + Math.abs(number(value)), 0);
  }

  function characterPower(profile, character) {
    return Math.round(equippedItems(profile, character).reduce((sum, item) => sum + sumItemPower(item) * (RARITIES[item.rarity]?.mult || 1), 0));
  }

  function statLine(stat, value) {
    const meta = STAT_META[stat] || { label: stat, suffix: '' };
    const sign = number(value) >= 0 ? '+' : '';
    return `<span class="equipment-stat"><b>${sign}${value}${meta.suffix}</b> ${escapeHtml(meta.label)}</span>`;
  }

  function rarityFromLevel(level, random = Math.random) {
    const l = Math.max(1, Math.floor(number(level, 1)));
    const weights = [
      ['common', Math.max(6, 58 - l * 0.55)],
      ['rare', 28 + Math.min(18, l * 0.20)],
      ['epic', Math.max(4, Math.min(22, 4 + l * 0.20))],
      ['legendary', Math.max(1, Math.min(14, Math.max(0, l - 16) * 0.18))],
      ['unique', Math.max(0, Math.min(7, Math.max(0, l - 34) * 0.10))],
      ['relic', Math.max(0, Math.min(4, Math.max(0, l - 55) * 0.06))]
    ];
    const total = weights.reduce((sum, [, weight]) => sum + weight, 0);
    let roll = random() * total;
    for (const [rarity, weight] of weights) {
      roll -= weight;
      if (roll <= 0) return rarity;
    }
    return 'common';
  }

  function pick(array, random = Math.random) {
    return array[Math.floor(random() * array.length)] || array[0];
  }

  function roleFromRoll(random = Math.random) {
    return random() < 0.62 ? 'commanders' : 'governors';
  }

  function buildItemName(item) {
    const set = EQUIPMENT_SETS[item.setId];
    if (set) return `${SLOTS[item.slot]?.name || 'Peça'} — ${set.name}`;
    const rarity = RARITIES[item.rarity]?.name || 'Comum';
    const base = pick(ITEM_WORDS[item.slot] || ['Peça']);
    const suffix = item.role === 'commanders' ? 'do comandante' : 'do governador';
    return `${base} ${rarity.toLowerCase()} ${suffix}`;
  }

  function generateStats(role, rarity, level, slot, random = Math.random, setId = null) {
    const pool = role === 'governors' ? GOVERNOR_STAT_POOL : COMMANDER_STAT_POOL;
    const count = rarity === 'common' ? 1 : rarity === 'rare' ? 2 : 3;
    const chosen = [];
    const setBias = EQUIPMENT_SETS[setId]?.statBias?.[role] || [];
    const preferred = setBias.length ? setBias
      : slot === 'weapon' && role === 'commanders' ? ['meleeAttack', 'rangedAttack']
      : slot === 'armor' && role === 'governors' ? ['meleeDefense', 'rangedDefense']
      : slot === 'helmet' ? (role === 'commanders' ? ['wallReduction', 'gateReduction'] : ['wallDefense', 'gateDefense'])
      : slot === 'hero' ? (role === 'commanders' ? ['meleeAttack', 'travelSpeed', 'lootBonus'] : ['meleeDefense', 'publicOrder', 'resourceProtection'])
      : pool;
    const candidates = [...preferred, ...pool.filter(stat => !preferred.includes(stat))];
    while (chosen.length < count && candidates.length) {
      const index = Math.floor(random() * candidates.length);
      const [stat] = candidates.splice(index, 1);
      chosen.push(stat);
    }
    const mult = RARITIES[rarity]?.mult || 1;
    const base = 2 + Math.sqrt(Math.max(1, level)) * 1.25;
    const stats = {};
    chosen.forEach((stat, index) => {
      const meta = STAT_META[stat];
      const scale = stat === 'publicOrder' ? 2.8 : stat.includes('Reduction') || stat.includes('Protection') || stat === 'findEquipment' ? 0.72 : 1;
      const value = Math.max(1, Math.round((base * mult * scale) * (0.72 + random() * 0.56) * (index === 0 ? 1 : 0.82)));
      stats[stat] = value;
      if (!meta) delete stats[stat];
    });
    return stats;
  }

  function randomDropSet(level, role, random = Math.random) {
    const l = Math.max(1, Math.floor(number(level, 1)));
    const chance = clamp(0.08 + l * 0.0032, 0.08, 0.34);
    if (random() > chance) return null;
    const available = l >= 65 ? SET_ORDER : l >= 45 ? SET_ORDER.filter(id => id !== 'imperial_relic') : l >= 25 ? ['falken_baron', 'royal_warrior', 'fortress_guardian', 'raider', 'stone_defender'] : ['falken_baron', 'raider', 'stone_defender'];
    if (role === 'governors') {
      const defenseSets = available.filter(id => ['fortress_guardian', 'stone_defender', 'imperial_relic', 'falken_baron'].includes(id));
      return pick(defenseSets.length ? defenseSets : available, random);
    }
    const attackSets = available.filter(id => ['falken_baron', 'royal_warrior', 'raider', 'imperial_relic'].includes(id));
    return pick(attackSets.length ? attackSets : available, random);
  }

  function createEquipment(level, options = {}) {
    const random = options.random || Math.random;
    const role = options.role || roleFromRoll(random);
    const rarity = options.rarity || rarityFromLevel(level, random);
    const slot = options.slot || pick(SLOT_ORDER, random);
    const setId = EQUIPMENT_SETS[options.setId] ? options.setId : (options.allowSetDrop ? randomDropSet(level, role, random) : null);
    const item = {
      id: uid('eq'),
      role,
      slot,
      rarity,
      setId,
      level: Math.max(1, Math.floor(number(level, 1))),
      icon: EQUIPMENT_SETS[setId]?.icon || SLOTS[slot]?.icon || '◆',
      stats: generateStats(role, rarity, level, slot, random, setId),
      source: options.source || 'Barão Falken',
      createdAt: Date.now()
    };
    item.name = buildItemName(item);
    return item;
  }

  function dropChance(profile, targetLevel, mission = null) {
    const bonus = commanderBonuses(profile, mission).findEquipment || 0;
    return clamp(0.22 + Math.min(80, Math.max(1, targetLevel)) * 0.0055 + bonus / 100, 0.18, 0.78);
  }

  function awardBaronDrop(context, target, options = {}) {
    const profile = context.getProfile?.();
    const state = ensureState(profile);
    if (!profile || !state || !target || options.win === false) return null;
    const defeatedLevel = Math.max(1, Math.floor(number(options.defeatedLevel, target.level || 1)));
    const chance = dropChance(profile, defeatedLevel, options.mission);
    if (Math.random() > chance) return null;
    const item = createEquipment(defeatedLevel, { source: target.name || 'Barão Falken', allowSetDrop: true });
    state.inventory.push(item);
    const rarity = RARITIES[item.rarity];
    const set = EQUIPMENT_SETS[item.setId];
    const roleName = item.role === 'governors' ? 'Governador' : 'Comandante';
    if (!options.suppressReport) {
      profile.reports = Array.isArray(profile.reports) ? profile.reports : [];
      profile.reports.push({
        id: context.uid?.('r') || uid('r'),
        at: context.now?.() || Date.now(),
        title: `Equipamento encontrado: ${item.name}`,
        result: 'info',
        text: `As tropas encontraram ${item.name} (${rarity.name}${set ? ` · ${set.name}` : ''}) ao derrotar o Barão Falken de nível ${defeatedLevel}. Pode ser equipado num ${roleName}.`
      });
    }
    context.toast?.(`Equipamento encontrado: ${item.name}`, 'success');
    return item;
  }

  function missionCommander(profile) {
    const character = activeCommander(profile);
    const bonuses = commanderBonuses(profile);
    return character ? {
      commanderId: character.id,
      commanderName: character.name,
      commanderBonuses: bonuses
    } : {};
  }

  function percentBonus(profile, mission, key) {
    return number((mission?.commanderBonuses || commanderBonuses(profile, mission))[key], 0);
  }

  function applyCommanderAttackPower(profile, mission, power, mode = 'mixed') {
    const bonuses = mission?.commanderBonuses || commanderBonuses(profile, mission);
    const melee = number(bonuses.meleeAttack, 0);
    const ranged = number(bonuses.rangedAttack, 0);
    const mixed = mode === 'melee' ? melee : mode === 'ranged' ? ranged : (melee + ranged) / 2;
    return power * (1 + mixed / 100);
  }

  function lootMultiplier(profile, mission) {
    return 1 + percentBonus(profile, mission, 'lootBonus') / 100;
  }

  function travelSpeedMultiplier(profile) {
    return 1 + number(commanderBonuses(profile).travelSpeed, 0) / 100;
  }


  function rarityMaxLevel(item) {
    // Mantém o limite global atual do jogo: todos os equipamentos podem chegar ao nível 80.
    // A raridade influencia o custo, a chance e a força da melhoria, não bloqueia a progressão.
    return 80;
  }

  function upgradeChance(item) {
    const rarity = RARITIES[item?.rarity] || RARITIES.common;
    const level = clamp(Math.floor(number(item?.level, 1)), 1, rarityMaxLevel(item));
    const rarityPenalty = rarity.mult * 5.5;
    const levelPenalty = level * 0.72;
    return clamp(Math.round(92 - levelPenalty - rarityPenalty), 18, 88);
  }

  function upgradeCost(item) {
    const rarity = RARITIES[item?.rarity] || RARITIES.common;
    const level = Math.max(1, Math.floor(number(item?.level, 1)));
    const next = Math.min(rarityMaxLevel(item), level + 1);
    const slotFactor = item?.slot === 'hero' ? 1.55 : item?.slot === 'look' ? 1.35 : item?.slot === 'artifact' ? 1.25 : 1;
    const setFactor = item?.setId ? 1.18 : 1;
    const coins = Math.round((280 + next * next * 42) * rarity.mult * slotFactor * setFactor);
    const gems = Math.max(1, Math.round((next * 0.42 + rarity.mult * 5.5) * slotFactor * setFactor));
    return { coins, gems };
  }

  function improvedStats(item) {
    const rarity = RARITIES[item?.rarity] || RARITIES.common;
    const nextLevel = Math.min(rarityMaxLevel(item), Math.floor(number(item?.level, 1)) + 1);
    const nextStats = {};
    Object.entries(item?.stats || {}).forEach(([stat, value]) => {
      const meta = STAT_META[stat];
      if (!meta) return;
      const baseGain = stat === 'publicOrder'
        ? Math.max(2, Math.round(1 + Math.sqrt(nextLevel) * 0.62 * rarity.mult))
        : Math.max(1, Math.round(0.45 + Math.sqrt(nextLevel) * 0.18 * rarity.mult));
      nextStats[stat] = Math.max(number(value, 0) + baseGain, number(value, 0) + 1);
    });
    return nextStats;
  }

  function statCompareLines(current = {}, next = {}) {
    const keys = Array.from(new Set([...Object.keys(current || {}), ...Object.keys(next || {})])).filter(key => STAT_META[key]);
    if (!keys.length) return '<div class="equipment-smith-empty">Esta peça não tem bónus para melhorar.</div>';
    return keys.map(stat => {
      const meta = STAT_META[stat];
      const before = number(current[stat], 0);
      const after = number(next[stat], before);
      return `<div class="equipment-smith-stat"><span>${escapeHtml(meta.label)}</span><strong>+${before}${meta.suffix}</strong><b>→</b><em>+${after}${meta.suffix}</em></div>`;
    }).join('');
  }

  function smithState(profile) {
    const state = ensureState(profile);
    if (!state.smith || typeof state.smith !== 'object') state.smith = {};
    if (!state.inventory.some(item => item.id === state.smith.selectedItemId)) state.smith.selectedItemId = state.inventory[0]?.id || null;
    return state.smith;
  }

  function selectedSmithItem(profile) {
    const state = ensureState(profile);
    const smith = smithState(profile);
    return findItemById(state, smith.selectedItemId) || state.inventory[0] || null;
  }

  function renderSmithItemButton(item, selected) {
    const rarity = RARITIES[item.rarity] || RARITIES.common;
    const set = EQUIPMENT_SETS[item.setId];
    return `<button class="equipment-smith-item ${selected ? 'active' : ''}" data-action="equipment-smith-select" data-item-id="${escapeHtml(item.id)}" style="--rarity:${set?.color || rarity.color}">
      <span class="equipment-smith-item-icon">${item.icon}</span>
      <span><b>${escapeHtml(item.name)}</b><small>${escapeHtml(rarity.name)} • Nv. ${item.level} • ${escapeHtml(SLOTS[item.slot]?.name || item.slot)}${set ? ` • ${escapeHtml(set.short)}` : ''}</small></span>
    </button>`;
  }

  function renderSmith(context) {
    const profile = context.getProfile();
    const state = ensureState(profile);
    const smith = smithState(profile);
    const item = selectedSmithItem(profile);
    const format = typeof context.format === 'function' ? context.format : value => String(Math.floor(Number(value) || 0));
    const inventory = [...state.inventory].sort((a, b) => (b.level - a.level) || (sumItemPower(b) - sumItemPower(a)));

    if (!inventory.length) {
      context.getContent().innerHTML = `<div class="view equipment-view equipment-smith-view">
        ${context.viewHeader('⚒️ Ferreiro', 'Melhora equipamentos de Comandantes e Governadores.')}
        <div class="equipment-smith-empty-panel">
          <h3>Ainda não tens equipamentos</h3>
          <p>Derrota Barões Falken para obter equipamentos. Depois poderás melhorar as peças aqui.</p>
        </div>
      </div>`;
      return true;
    }

    const maxLevel = rarityMaxLevel(item);
    const isMax = Number(item.level) >= maxLevel;
    const cost = upgradeCost(item);
    const chance = upgradeChance(item);
    const nextStats = improvedStats(item);
    const rarity = RARITIES[item.rarity] || RARITIES.common;
    const set = EQUIPMENT_SETS[item.setId];
    const equipped = itemEquippedBy(state, item.id);
    const last = smith.lastResult ? `<div class="equipment-smith-result ${smith.lastResult.success ? 'success' : 'fail'}">${escapeHtml(smith.lastResult.text)}</div>` : '';

    const html = `<div class="view equipment-view equipment-smith-view">
      ${context.viewHeader('⚒️ Ferreiro', 'Escolhe uma peça, vê o próximo nível e tenta melhorar com moedas ou garantir com coroas.')}
      <div class="equipment-smith-shell">
        <aside class="equipment-smith-list">
          <h3>Inventário</h3>
          ${inventory.map(invItem => renderSmithItemButton(invItem, invItem.id === item.id)).join('')}
        </aside>
        <section class="equipment-smith-card" style="--rarity:${set?.color || rarity.color}">
          <div class="equipment-smith-selected">
            <span class="equipment-smith-big-icon">${item.icon}</span>
            <div><small>${escapeHtml(rarity.name)}${set ? ` · ${escapeHtml(set.name)}` : ''}</small><h2>${escapeHtml(item.name)}</h2><p>${escapeHtml(SLOTS[item.slot]?.name || item.slot)} para ${item.role === 'governors' ? 'Governador' : 'Comandante'}${equipped ? ` · Equipado em ${escapeHtml(equipped.character?.name || '')}` : ''}</p></div>
          </div>
          <div class="equipment-smith-levels"><span>Nível atual <b>${item.level}</b></span><span>Próximo nível <b>${isMax ? 'Máximo' : item.level + 1}</b></span></div>
          <div class="equipment-smith-stats">${statCompareLines(item.stats, nextStats)}</div>
          ${last}
        </section>
        <aside class="equipment-smith-upgrade">
          <h3>Melhoria</h3>
          <div class="equipment-smith-chance"><span>Chance de sucesso</span><strong>${isMax ? '—' : `${chance}%`}</strong></div>
          <div class="equipment-smith-cost"><span>Moedas</span><b>🪙 ${format(cost.coins)}</b></div>
          <div class="equipment-smith-cost"><span>Garantia</span><b>💎 ${format(cost.gems)} coroas</b></div>
          <p class="equipment-smith-note">Se falhar, a peça não desaparece e mantém o nível atual. Com coroas, a melhoria é garantida.</p>
          <button class="action-btn" data-action="equipment-smith-upgrade" ${isMax ? 'disabled' : ''}>Melhorar com moedas</button>
          <button class="secondary-btn" data-action="equipment-smith-guarantee" ${isMax ? 'disabled' : ''}>Garantir com coroas</button>
        </aside>
      </div>
    </div>`;
    context.getContent().innerHTML = html;
    return true;
  }

  function applyUpgrade(item) {
    item.level = Math.min(rarityMaxLevel(item), Math.floor(number(item.level, 1)) + 1);
    item.stats = improvedStats({ ...item, level: item.level - 1 });
    item.name = item.name || buildItemName(item);
    return item;
  }

  async function improveSelectedEquipment(context, guaranteed = false) {
    const profile = context.getProfile();
    const item = selectedSmithItem(profile);
    const state = ensureState(profile);
    const smith = smithState(profile);
    if (!item) {
      context.toast?.('Seleciona uma peça para melhorar.', 'error');
      return true;
    }
    if (Number(item.level) >= rarityMaxLevel(item)) {
      context.toast?.('Este equipamento já está no nível máximo.', 'error');
      return true;
    }
    profile.resources = profile.resources || {};
    const cost = upgradeCost(item);
    if (number(profile.resources.coins, 0) < cost.coins) {
      context.toast?.('Moedas insuficientes para melhorar o equipamento.', 'error');
      return true;
    }
    if (guaranteed && number(profile.resources.gems, 0) < cost.gems) {
      context.toast?.('Coroas insuficientes para garantir a melhoria.', 'error');
      return true;
    }
    profile.resources.coins = Math.max(0, number(profile.resources.coins, 0) - cost.coins);
    if (guaranteed) profile.resources.gems = Math.max(0, number(profile.resources.gems, 0) - cost.gems);
    const chance = upgradeChance(item);
    const success = guaranteed || Math.random() * 100 < chance;
    if (success) {
      const before = item.level;
      applyUpgrade(item);
      smith.lastResult = { success: true, text: `${item.name} melhorado do nível ${before} para ${item.level}.` };
      context.toast?.('Melhoria concluída com sucesso.', 'success');
    } else {
      smith.lastResult = { success: false, text: `A melhoria falhou. ${item.name} manteve o nível ${item.level}.` };
      context.toast?.('A melhoria falhou, mas a peça não foi perdida.', 'error');
    }
    context.updateHud?.();
    await context.persist?.(true);
    renderSmith(context);
    return true;
  }

  function itemCard(item, context, options = {}) {
    const rarity = RARITIES[item.rarity] || RARITIES.common;
    const set = EQUIPMENT_SETS[item.setId];
    const equipped = options.equipped;
    const canEquip = options.canEquip !== false;
    const stats = Object.entries(item.stats || {}).map(([stat, value]) => statLine(stat, value)).join('');
    return `<article class="equipment-item-card ${equipped ? 'is-equipped' : ''}" style="--rarity:${set?.color || rarity.color}">
      <div class="equipment-item-head"><span class="equipment-item-icon">${item.icon}</span><div><strong>${escapeHtml(item.name)}</strong><small>${escapeHtml(rarity.name)} • Nv. ${item.level} • ${escapeHtml(SLOTS[item.slot]?.name || item.slot)}</small>${set ? `<em class="equipment-set-tag">${escapeHtml(set.name)}</em>` : ''}</div></div>
      <div class="equipment-stats">${stats || '<span class="equipment-stat">Sem bónus</span>'}</div>
      ${equipped ? '<span class="equipment-equipped-label">Equipado</span>' : canEquip ? `<button class="action-btn equipment-mini-btn" data-action="equipment-equip" data-item-id="${escapeHtml(item.id)}">Equipar</button>` : ''}
    </article>`;
  }

  function renderSlot(slot, item, role) {
    const slotDef = SLOTS[slot];
    if (!item) {
      return `<div class="equipment-slot empty"><div class="equipment-slot-name">${slotDef.icon} ${escapeHtml(slotDef.name)}</div><div class="equipment-empty-slot">Vazio</div></div>`;
    }
    const rarity = RARITIES[item.rarity] || RARITIES.common;
    const set = EQUIPMENT_SETS[item.setId];
    return `<div class="equipment-slot filled" style="--rarity:${set?.color || rarity.color}">
      <div class="equipment-slot-name">${slotDef.icon} ${escapeHtml(slotDef.name)}</div>
      <div class="equipment-slot-item"><b>${escapeHtml(item.name)}</b><small>${escapeHtml(rarity.name)}${set ? ` · ${escapeHtml(set.short)}` : ''}</small></div>
      <button class="secondary-btn equipment-mini-btn" data-action="equipment-unequip" data-role="${role}" data-slot="${slot}">Remover</button>
    </div>`;
  }

  function summaryRows(bonuses, role) {
    const stats = Object.entries(STAT_META).filter(([, meta]) => meta.role === role);
    return stats.map(([stat, meta]) => {
      const value = number(bonuses[stat], 0);
      return `<div class="equipment-summary-row ${value ? 'has-value' : ''}"><span>${escapeHtml(meta.label)}</span><strong>${value >= 0 ? '+' : ''}${value}${meta.suffix}</strong></div>`;
    }).join('');
  }

  function renderSetSummary(profile, character, role) {
    const counts = setCounts(profile, character);
    const cards = SET_ORDER.map(setId => {
      const set = EQUIPMENT_SETS[setId];
      const count = counts[setId] || 0;
      const active = [2, 4, 6].filter(threshold => count >= threshold);
      const next = [2, 4, 6].find(threshold => count < threshold);
      const activeText = active.length ? `Ativo: ${active.join('/')} peças` : 'Sem bónus ativo';
      const nextText = next ? `Próximo bónus: ${next} peças` : 'Conjunto completo';
      const bonuses = active.length
        ? active.map(threshold => Object.entries(set.bonuses?.[role]?.[threshold] || {}).map(([stat, value]) => statLine(stat, value)).join('')).join('')
        : '';
      return `<article class="equipment-set-card ${count ? 'has-pieces' : ''}" style="--set-color:${set.color}">
        <div><strong>${set.icon} ${escapeHtml(set.name)}</strong><small>${count}/6 peças · ${activeText} · ${nextText}</small></div>
        ${bonuses ? `<div class="equipment-set-bonuses">${bonuses}</div>` : ''}
      </article>`;
    }).join('');
    return `<div class="equipment-set-summary"><h3>Bónus de conjunto</h3>${cards}</div>`;
  }

  function characterButton(character, active, profile, role) {
    const power = characterPower(profile, character);
    return `<button class="equipment-character-btn ${active ? 'active' : ''}" data-action="equipment-select-character" data-role="${role}" data-id="${escapeHtml(character.id)}">
      <span>${role === 'commanders' ? '⚔️' : '🛡️'}</span>
      <b>${escapeHtml(character.name)}</b>
      <small>Nv. ${character.level} • Poder ${power}</small>
    </button>`;
  }

  function render(role, context) {
    const profile = context.getProfile();
    const state = ensureState(profile);
    const def = roleDef(role);
    const characters = state[def.listKey] || [];
    const selected = selectedCharacter(state, role);
    const equipped = SLOT_ORDER.map(slot => [slot, findItemById(state, selected?.slots?.[slot])]);
    const bonuses = characterBonuses(profile, selected);
    const filteredItems = state.inventory.filter(item => item.role === role);
    const inventory = filteredItems.length
      ? filteredItems.sort((a, b) => sumItemPower(b) - sumItemPower(a)).map(item => itemCard(item, context, { equipped: Boolean(itemEquippedBy(state, item.id)), canEquip: true })).join('')
      : `<div class="equipment-empty-inventory">Ainda não tens equipamento para ${def.plural.toLowerCase()}. Derrota Barões Falken para ter chance de encontrar peças.</div>`;

    const activeNote = role === 'commanders'
      ? 'O comandante selecionado acompanha automaticamente os ataques.'
      : 'O governador selecionado protege o castelo e ficará ligado à defesa.';

    const html = `<div class="view equipment-view equipment-${role}">
      ${context.viewHeader(`${def.icon} ${def.plural}`, `${activeNote} Equipamentos encontrados nos Barões podem ser equipados aqui.`)}
      <div class="equipment-shell">
        <aside class="equipment-character-list">
          <h3>${def.plural}</h3>
          ${characters.map(character => characterButton(character, character.id === selected?.id, profile, role)).join('')}
        </aside>
        <section class="equipment-paperdoll">
          <div class="equipment-hero-card">
            <div class="equipment-hero-portrait">${def.icon}</div>
            <div><small>${def.singular} ativo</small><h2>${escapeHtml(selected?.name || def.singular)}</h2><p>Especializado em ${def.focus}.</p></div>
          </div>
          <div class="equipment-slots">${equipped.map(([slot, item]) => renderSlot(slot, item, role)).join('')}</div>
        </section>
        <aside class="equipment-summary">
          <h3>Bónus totais</h3>
          <div class="equipment-summary-list">${summaryRows(bonuses, role)}</div>
          ${renderSetSummary(profile, selected, role)}
          <h3>Inventário</h3>
          <div class="equipment-inventory">${inventory}</div>
        </aside>
      </div>
    </div>`;
    context.getContent().innerHTML = html;
    return true;
  }

  function equipItem(profile, role, characterId, itemId) {
    const state = ensureState(profile);
    const def = roleDef(role);
    const character = state[def.listKey].find(item => item.id === characterId) || selectedCharacter(state, role);
    const item = findItemById(state, itemId);
    if (!character || !item || item.role !== role) return false;
    const previous = itemEquippedBy(state, item.id);
    if (previous?.character?.slots) previous.character.slots[previous.slot] = null;
    character.slots[item.slot] = item.id;
    state[def.activeKey] = character.id;
    return true;
  }

  function unequip(profile, role, characterId, slot) {
    const state = ensureState(profile);
    const def = roleDef(role);
    const character = state[def.listKey].find(item => item.id === characterId) || selectedCharacter(state, role);
    if (!character || !SLOTS[slot]) return false;
    character.slots[slot] = null;
    return true;
  }

  async function handleAction(action, element, context) {
    if (!action || !action.startsWith('equipment-')) return false;
    const profile = context.getProfile();
    const state = ensureState(profile);
    const currentRole = context.getActiveView?.() || (document.querySelector('.equipment-view.equipment-governors') ? 'governors' : 'commanders');
    if (action === 'equipment-smith-select') {
      state.smith = state.smith || {};
      if (state.inventory.some(item => item.id === element.dataset.itemId)) state.smith.selectedItemId = element.dataset.itemId;
      state.smith.lastResult = null;
      renderSmith(context);
      context.persist?.(true);
      return true;
    }
    if (action === 'equipment-smith-upgrade') return improveSelectedEquipment(context, false);
    if (action === 'equipment-smith-guarantee') return improveSelectedEquipment(context, true);
    if (action === 'equipment-select-character') {
      const role = element.dataset.role || currentRole;
      const def = roleDef(role);
      if (state[def.listKey].some(character => character.id === element.dataset.id)) state[def.activeKey] = element.dataset.id;
      render(role, context);
      context.persist?.(true);
      return true;
    }
    if (action === 'equipment-equip') {
      const role = currentRole;
      const def = roleDef(role);
      const character = selectedCharacter(state, role);
      if (!equipItem(profile, role, character?.id, element.dataset.itemId)) {
        context.toast?.('Esta peça não pode ser equipada aqui.', 'error');
        return true;
      }
      context.toast?.('Equipamento aplicado.', 'success');
      render(role, context);
      context.persist?.(true);
      return true;
    }
    if (action === 'equipment-unequip') {
      const role = element.dataset.role || currentRole;
      const character = selectedCharacter(state, role);
      unequip(profile, role, character?.id, element.dataset.slot);
      render(role, context);
      context.persist?.(true);
      return true;
    }
    return false;
  }

  globalThis.ReinosEquipmentSystem = Object.freeze({
    VERSION,
    ensureState,
    render,
    renderSmith,
    handleAction,
    createEquipment,
    awardBaronDrop,
    missionCommander,
    commanderBonuses,
    governorBonuses,
    applyCommanderAttackPower,
    lootMultiplier,
    travelSpeedMultiplier,
    EQUIPMENT_SETS,
    SET_ORDER,
    SLOTS,
    SLOT_ORDER,
    RARITIES
  });
})();
