'use strict';

/**
 * Planeamento final da viagem antes do envio de um ataque.
 *
 * Responsabilidades:
 * - ler o nível atual dos Estábulos já construídos;
 * - disponibilizar as montadas desbloqueadas por esse nível;
 * - calcular tempo, chegada e custo com base na distância e nas tropas;
 * - confirmar a montada sem retirar tropas ou recursos diretamente;
 * - manter este sistema separado da formação e da resolução do combate.
 */
(() => {
  const VERSION = 1;
  const MINIMUM_TRAVEL_MS = 1000;

  const MOUNTS = Object.freeze([
    Object.freeze({
      id: 'horse',
      name: 'Cavalo',
      icon: '🐴',
      requiredStableLevel: 1,
      reduction: 0.20,
      currency: 'coins',
      description: 'Diminui o tempo de viagem de ida e volta em 20%.'
    }),
    Object.freeze({
      id: 'warhorse',
      name: 'Cavalo de guerra',
      icon: '🐎',
      requiredStableLevel: 2,
      reduction: 0.30,
      currency: 'gems',
      description: 'Diminui o tempo de viagem de ida e volta em 30%.'
    }),
    Object.freeze({
      id: 'steed',
      name: 'Corcel',
      icon: '♞',
      requiredStableLevel: 3,
      reduction: 0.41,
      currency: 'gems',
      description: 'Diminui o tempo de viagem de ida e volta em 41%.'
    })
  ]);

  let pending = null;

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

  function totalTroops(troops) {
    return Object.values(troops || {}).reduce((sum, count) => sum + Math.max(0, Math.floor(number(count))), 0);
  }

  function stableLevel(profile) {
    return (profile?.buildings || [])
      .filter(building => building.type === 'stables' && building.status !== 'constructing')
      .reduce((highest, building) => Math.max(highest, Math.max(0, Math.floor(number(building.level)))), 0);
  }

  function mountById(id) {
    return MOUNTS.find(mount => mount.id === id) || null;
  }

  function highestUnlockedMount(level) {
    return [...MOUNTS].reverse().find(mount => level >= mount.requiredStableLevel) || null;
  }

  function travelLoad(distance, troopCount) {
    const troopFactor = Math.max(1, Math.sqrt(Math.max(1, troopCount) / 16));
    return Math.max(1, number(distance) * troopFactor);
  }

  function mountCost(mount, distance, troopCount, level) {
    if (!mount) return { currency: null, amount: 0 };
    const load = travelLoad(distance, troopCount);
    let amount = 0;
    if (mount.id === 'horse') amount = Math.ceil(load * 6);
    if (mount.id === 'warhorse') amount = Math.ceil(load * 0.5);
    if (mount.id === 'steed') amount = Math.ceil(load);

    // Níveis acima do terceiro mantêm o progresso existente e reduzem
    // ligeiramente o custo, sem criar novas montadas nesta fase.
    const extraLevels = Math.max(0, Math.floor(number(level)) - 3);
    const discount = Math.min(0.30, extraLevels * 0.05);
    amount = Math.max(mount.currency === 'coins' ? 1 : (mount.id === 'steed' ? 2 : 1), Math.ceil(amount * (1 - discount)));
    return { currency: mount.currency, amount };
  }

  function calculateTravelMs(baseTravelMs, mount) {
    const base = Math.max(MINIMUM_TRAVEL_MS, Math.round(number(baseTravelMs, MINIMUM_TRAVEL_MS)));
    if (!mount) return base;
    return Math.max(MINIMUM_TRAVEL_MS, Math.round(base * (1 - mount.reduction)));
  }

  function routeFor(order, context) {
    const profile = context.getProfile();
    const origin = profile?.worldPosition || { x: 0, y: 0 };
    const target = order?.target || {};
    const destination = { x: number(target.x), y: number(target.y) };
    const distance = Math.hypot(destination.x - number(origin.x), destination.y - number(origin.y));
    return globalThis.ReinosMarchTravelTime?.route?.(origin, destination) || {
      from: origin,
      to: destination,
      distance,
      travelMs: Math.max(MINIMUM_TRAVEL_MS, Math.round(distance * 6000)),
      secondsPerCoordinate: 6,
      coordinatesPerMinute: 10
    };
  }

  function formatDate(timestamp) {
    return new Date(timestamp).toLocaleDateString('pt-PT', { day: '2-digit', month: '2-digit', year: 'numeric' });
  }

  function formatClock(timestamp) {
    return new Date(timestamp).toLocaleTimeString('pt-PT', { hour: '2-digit', minute: '2-digit' });
  }

  function resourceIcon(currency) {
    if (currency === 'coins') return globalThis.ReinosResourceIcons?.icon?.('coins') || '🪙';
    if (currency === 'gems') return globalThis.ReinosResourceIcons?.icon?.('gems') || '💎';
    return '';
  }

  function selectionData(mountId = pending?.selectedMountId) {
    if (!pending) return null;
    const profile = pending.context.getProfile();
    const level = stableLevel(profile);
    const route = pending.route;
    const mount = mountById(mountId);
    const unlocked = Boolean(mount && level >= mount.requiredStableLevel);
    const selectedMount = unlocked ? mount : null;
    const troopCount = totalTroops(pending.order.troops);
    const cost = mountCost(selectedMount, route.distance, troopCount, level);
    const commanderSpeed = globalThis.ReinosEquipmentSystem?.travelSpeedMultiplier?.(profile) || 1;
    const travelMs = Math.max(MINIMUM_TRAVEL_MS, Math.round(calculateTravelMs(route.travelMs, selectedMount) / commanderSpeed));
    return {
      stableLevel: level,
      mount: selectedMount,
      mountId: selectedMount?.id || 'on-foot',
      mountName: selectedMount?.name || 'Sem montada',
      reduction: selectedMount?.reduction || 0,
      commanderSpeedBonus: Math.max(0, commanderSpeed - 1),
      cost,
      baseTravelMs: route.travelMs,
      travelMs,
      distance: route.distance,
      troopCount,
      arrivalAt: pending.context.now() + travelMs,
      returnTravelMs: travelMs
    };
  }

  function mountCard(mount, selected, level, route, troopCount, profile, context) {
    const unlocked = level >= mount.requiredStableLevel;
    const cost = mountCost(mount, route.distance, troopCount, level);
    const affordable = (number(profile?.resources?.[cost.currency]) >= cost.amount);
    const disabledClass = unlocked ? '' : ' is-locked';
    const selectedClass = selected === mount.id ? ' is-selected' : '';
    const unaffordableClass = unlocked && !affordable ? ' is-unaffordable' : '';
    const status = unlocked
      ? `<span class="travel-mount-cost">${resourceIcon(cost.currency)} ${context.format(cost.amount)}</span>`
      : `<span class="travel-mount-lock">🔒 Estábulos nv. ${mount.requiredStableLevel}</span>`;
    return `<button type="button" class="travel-mount-card${selectedClass}${disabledClass}${unaffordableClass}" data-action="travel-plan-select" data-mount="${mount.id}" ${unlocked ? '' : 'disabled'}>
      <span class="travel-mount-art ${mount.id}" aria-hidden="true">${mount.icon}</span>
      <strong>${context.escapeHtml(mount.name)}</strong>
      <span class="travel-mount-bonus">−${Math.round(mount.reduction * 100)}% tempo</span>
      ${status}
      <span class="travel-mount-radio" aria-hidden="true"></span>
      <span class="travel-mount-help" role="tooltip"><b>${context.escapeHtml(mount.name)}</b>${context.escapeHtml(mount.description)}</span>
    </button>`;
  }

  function plannerHtml() {
    if (!pending) return '';
    const { context, order, route } = pending;
    const profile = context.getProfile();
    const level = stableLevel(profile);
    const troopCount = totalTroops(order.troops);
    const selected = selectionData();
    const hasStables = level > 0;
    const selectedCost = selected.cost.amount > 0
      ? `${resourceIcon(selected.cost.currency)} ${context.format(selected.cost.amount)}`
      : 'Grátis';
    const currentBalance = selected.cost.currency ? number(profile.resources?.[selected.cost.currency]) : 0;
    const affordable = !selected.cost.currency || currentBalance >= selected.cost.amount;

    return `<div id="travel-planner" class="travel-planner-shell">
      <header class="travel-planner-header">
        <div class="travel-commander" aria-hidden="true">🪖</div>
        <div>
          <small>Planeamento de viagem</small>
          <h3>${context.escapeHtml(order.target.name)}</h3>
          <span>Estábulos atuais: nível ${level}</span>
        </div>
      </header>

      <section class="travel-arrival-strip">
        <div><span>Chegada</span><strong data-travel-arrival-date>${formatDate(selected.arrivalAt)}</strong><strong data-travel-arrival-time>${formatClock(selected.arrivalAt)}</strong></div>
        <div><span>Distância</span><strong>${context.format(Math.round(route.distance * 10) / 10)} coordenadas</strong></div>
        <div><span>Tropas</span><strong>${context.format(troopCount)}</strong></div>
      </section>

      <section class="travel-summary-row">
        <div><span>Tempo normal</span><strong>${context.formatTime(route.travelMs)}</strong></div>
        <div class="is-highlight"><span>Tempo selecionado</span><strong data-travel-selected-time>${context.formatTime(selected.travelMs)}</strong></div>
        <div><span>Ida e volta</span><strong data-travel-round-time>${context.formatTime(selected.travelMs * 2)}</strong></div>
        <div><span>Custo</span><strong data-travel-selected-cost>${selectedCost}</strong></div>
      </section>

      ${hasStables ? `<section class="travel-mount-grid">
        ${MOUNTS.map(mount => mountCard(mount, selected.mountId, level, route, troopCount, profile, context)).join('')}
      </section>` : `<section class="travel-no-stables">
        <span aria-hidden="true">🐴</span>
        <div><strong>Sem Estábulos</strong><p>O ataque seguirá à velocidade normal. Constrói Estábulos para desbloquear montadas mais rápidas.</p></div>
      </section>`}

      <footer class="travel-planner-note ${affordable ? '' : 'is-warning'}">
        <span>${affordable ? '✓' : '!'}</span>
        <p data-travel-affordability>${affordable
          ? `${context.escapeHtml(selected.mountName)} selecionado. O mesmo tempo será usado no regresso.`
          : `Não tens ${selected.cost.currency === 'coins' ? 'moedas' : 'coroas'} suficientes para esta montada.`}</p>
      </footer>
    </div>`;
  }

  function footerHtml() {
    const selection = selectionData();
    const profile = pending.context.getProfile();
    const canAfford = !selection.cost.currency || number(profile.resources?.[selection.cost.currency]) >= selection.cost.amount;
    return `<button class="secondary-btn" data-action="travel-plan-back">← Voltar</button>
      <button class="travel-confirm-btn" data-action="travel-plan-confirm" ${canAfford ? '' : 'disabled'}>✓ ENVIAR ATAQUE</button>`;
  }

  function render() {
    if (!pending) return;
    pending.context.openModal('Planeamento de Viagem', plannerHtml(), footerHtml());
    document.querySelector('.modal')?.classList.add('travel-planner-modal');
  }

  function open(order, context, callbacks = {}) {
    const route = routeFor(order, context);
    const level = stableLevel(context.getProfile());
    const preferred = MOUNTS.find(mount => level >= mount.requiredStableLevel) || null;
    pending = {
      order,
      context,
      route,
      selectedMountId: preferred?.id || 'on-foot',
      onConfirm: callbacks.onConfirm,
      onBack: callbacks.onBack,
      onCancel: callbacks.onCancel
    };
    render();
    return true;
  }

  async function confirm() {
    if (!pending) return false;
    const selection = selectionData();
    const profile = pending.context.getProfile();
    if (selection.cost.currency && number(profile.resources?.[selection.cost.currency]) < selection.cost.amount) {
      pending.context.toast('Não tens recursos suficientes para esta montada.', 'error');
      render();
      return false;
    }
    const callback = pending.onConfirm;
    const active = pending;
    const handled = await callback?.(selection, active.order);
    if (handled !== false) pending = null;
    return handled !== false;
  }

  async function handleAction(action, actionElement) {
    if (!pending) return false;
    if (action === 'travel-plan-select') {
      const mount = mountById(actionElement.dataset.mount);
      const level = stableLevel(pending.context.getProfile());
      if (!mount || level < mount.requiredStableLevel) return true;
      pending.selectedMountId = mount.id;
      render();
      return true;
    }
    if (action === 'travel-plan-back') {
      const callback = pending.onBack;
      await callback?.();
      return true;
    }
    if (action === 'travel-plan-confirm') {
      await confirm();
      return true;
    }
    if (action === 'travel-plan-cancel') {
      const callback = pending.onCancel;
      pending = null;
      await callback?.();
      return true;
    }
    return false;
  }

  globalThis.ReinosTravelPlanning = Object.freeze({
    VERSION,
    MOUNTS,
    stableLevel,
    highestUnlockedMount,
    mountCost,
    calculateTravelMs,
    open,
    handleAction
  });
})();
