'use strict';

/**
 * Sistema modular de cancelamento de ataques.
 *
 * Regras:
 * - apenas marchas de ida podem ser canceladas;
 * - o prazo máximo é de 10 minutos após a partida;
 * - ao cancelar, o exército regressa a partir da posição atual;
 * - tropas e ferramentas só ficam disponíveis quando regressarem ao castelo;
 * - depois do prazo, ou depois de chegar ao alvo, a ordem torna-se definitiva.
 */
(() => {
  const VERSION = 1;
  const CANCEL_WINDOW_MS = 10 * 60 * 1000;

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

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

  function launchAt(mission) {
    return number(mission?.launchStartedAt, number(mission?.startedAt, 0));
  }

  function cancelUntil(mission) {
    return number(mission?.cancelWindowEndsAt, launchAt(mission) + CANCEL_WINDOW_MS);
  }

  function isOutgoing(mission) {
    return Boolean(mission) && (mission.state || 'outgoing') === 'outgoing';
  }

  function canCancel(mission, currentTime = Date.now()) {
    if (!isOutgoing(mission) || mission.cancelled) return false;
    const arrivalAt = number(mission.endAt, 0);
    return currentTime < arrivalAt && currentTime <= cancelUntil(mission);
  }

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

  function interpolate(from, to, progress) {
    const p = clamp(number(progress), 0, 1);
    return {
      x: number(from?.x) + (number(to?.x) - number(from?.x)) * p,
      y: number(from?.y) + (number(to?.y) - number(from?.y)) * p
    };
  }

  function currentPosition(mission, currentTime) {
    const origin = mission?.originPosition || { x: 0, y: 0 };
    const target = mission?.targetPosition || origin;
    const started = launchAt(mission);
    const duration = Math.max(1, number(mission?.originalTravelMs, number(mission?.travelMs, number(mission?.endAt) - started)));
    const progress = clamp((currentTime - started) / duration, 0, 1);
    return interpolate(origin, target, progress);
  }

  function toolSnapshot(mission) {
    const summarized = globalThis.ReinosAttackTools?.summarizePlan?.(mission?.attackPlan?.waves || []);
    return globalThis.ReinosSiegeTools?.normalizeToolMap?.(summarized) || { ...(summarized || {}) };
  }

  function toolTotal(tools) {
    return Object.values(tools || {}).reduce((sum, value) => sum + Math.max(0, Math.floor(number(value))), 0);
  }

  function toolText(tools, context) {
    const catalog = globalThis.ReinosSiegeTools?.CATALOG || {};
    const entries = Object.entries(tools || {})
      .filter(([, amount]) => number(amount) > 0)
      .map(([type, amount]) => `${context.format(Math.floor(number(amount)))} ${catalog[type]?.name || type}`);
    return entries.length ? entries.join(', ') : 'nenhuma ferramenta';
  }

  function findMission(context, missionId) {
    return context.getProfile()?.missions?.find(mission => mission.id === missionId) || null;
  }

  function missionStatus(mission, context) {
    const currentTime = context.now();
    if (mission.cancelled && mission.state === 'returning') {
      return {
        label: 'Ataque cancelado — em regresso',
        remaining: Math.max(0, number(mission.endAt) - currentTime),
        cancellable: false
      };
    }
    if (mission.state === 'returning') {
      return { label: 'Exército em regresso', remaining: Math.max(0, number(mission.endAt) - currentTime), cancellable: false };
    }
    if (mission.state === 'resolving') {
      return { label: 'Batalha em resolução', remaining: 0, cancellable: false };
    }
    const remaining = Math.max(0, number(mission.endAt) - currentTime);
    return {
      label: canCancel(mission, currentTime) ? 'Ataque em marcha' : 'Ataque confirmado',
      remaining,
      cancellable: canCancel(mission, currentTime)
    };
  }

  function missionQueueControls(mission, context) {
    if (!mission || mission.state === 'done') return '';
    const currentTime = context.now();
    if (mission.cancelled && mission.state === 'returning') {
      return `<div class="attack-cancel-status cancelled"><span>Ordem cancelada</span><small>As tropas e ferramentas regressam ao castelo.</small></div><button class="secondary-btn attack-mission-details" data-action="mission-open" data-id="${context.escapeHtml(mission.id)}">Ver marcha</button>`;
    }
    if (!isOutgoing(mission)) {
      return `<button class="secondary-btn attack-mission-details" data-action="mission-open" data-id="${context.escapeHtml(mission.id)}">Ver marcha</button>`;
    }
    const deadline = cancelUntil(mission);
    if (canCancel(mission, currentTime)) {
      return `<div class="attack-cancel-status"><span>Cancelamento disponível</span><small data-cancel-window="${context.escapeHtml(mission.id)}">${context.formatTime(Math.max(0, deadline - currentTime))}</small></div><div class="btn-row attack-cancel-actions"><button class="secondary-btn" data-action="mission-open" data-id="${context.escapeHtml(mission.id)}">Detalhes</button><button class="danger-btn" data-action="mission-cancel" data-id="${context.escapeHtml(mission.id)}">Cancelar ataque</button></div>`;
    }
    return `<div class="attack-cancel-status locked"><span>Ordem definitiva</span><small>O prazo de 10 minutos terminou.</small></div><button class="secondary-btn attack-mission-details" data-action="mission-open" data-id="${context.escapeHtml(mission.id)}">Ver marcha</button>`;
  }

  function openMission(mission, context) {
    const currentTime = context.now();
    const status = missionStatus(mission, context);
    const deadline = cancelUntil(mission);
    const launched = new Date(launchAt(mission)).toLocaleString('pt-PT');
    const arrival = new Date(number(mission.endAt)).toLocaleString('pt-PT');
    const troops = totalTroops(mission.troops);
    const tools = mission.cancelledTools || toolSnapshot(mission);
    const canStillCancel = canCancel(mission, currentTime);
    const cancellationLine = isOutgoing(mission)
      ? `<div class="stats-line"><span>Prazo para cancelar</span><strong>${canStillCancel ? context.formatTime(Math.max(0, deadline - currentTime)) : 'Terminado'}</strong></div>`
      : '';
    const footer = canStillCancel
      ? `<button class="secondary-btn" data-action="modal-close">Fechar</button><button class="danger-btn" data-action="mission-cancel" data-id="${context.escapeHtml(mission.id)}">Cancelar ataque</button>`
      : `<button class="action-btn" data-action="modal-close">Fechar</button>`;

    context.openModal(`Marcha para ${context.escapeHtml(mission.targetName || 'alvo')}`, `
      <div class="attack-mission-card ${mission.cancelled ? 'is-cancelled' : ''}">
        <div class="attack-mission-card-title"><span>${mission.cancelled ? '↩️' : '⚔️'}</span><div><strong>${context.escapeHtml(status.label)}</strong><small>${context.escapeHtml(mission.targetName || 'Alvo')}</small></div></div>
        <div class="stats-line"><span>Tropas na marcha</span><strong>${context.format(troops)}</strong></div>
        <div class="stats-line"><span>Ferramentas</span><strong>${context.escapeHtml(toolText(tools, context))}</strong></div>
        ${mission.travelPlan ? `<div class="stats-line"><span>Montada</span><strong>${context.escapeHtml(mission.travelPlan.mountName || 'Sem montada')} ${mission.travelPlan.reduction ? `(−${Math.round(Number(mission.travelPlan.reduction) * 100)}%)` : ''}</strong></div>` : ''}
        <div class="stats-line"><span>Partida</span><strong>${context.escapeHtml(launched)}</strong></div>
        <div class="stats-line"><span>Chegada prevista</span><strong>${context.escapeHtml(arrival)}</strong></div>
        <div class="stats-line"><span>Tempo restante</span><strong>${context.formatTime(status.remaining)}</strong></div>
        ${cancellationLine}
        ${mission.cancelled ? '<p class="attack-cancel-note">A batalha não será realizada. As tropas e as ferramentas só voltarão ao inventário quando esta marcha chegar ao castelo.</p>' : ''}
      </div>`, footer);
  }

  function openCancelConfirmation(mission, context) {
    if (!canCancel(mission, context.now())) {
      context.toast('Este ataque já não pode ser cancelado.', 'error');
      return;
    }
    const elapsed = Math.max(0, context.now() - launchAt(mission));
    context.openModal('Cancelar ataque', `
      <p>Queres cancelar o ataque a <strong>${context.escapeHtml(mission.targetName || 'este alvo')}</strong>?</p>
      <p>O exército regressará a partir da posição atual. O regresso demorará aproximadamente <strong>${context.formatTime(Math.max(1000, elapsed))}</strong>.</p>
      <p>As tropas e ferramentas só voltarão a ficar disponíveis quando chegarem ao castelo.</p>`,
      `<button class="secondary-btn" data-action="modal-close">Manter ataque</button><button class="danger-btn" data-action="mission-cancel-confirm" data-id="${context.escapeHtml(mission.id)}">Confirmar cancelamento</button>`);
  }

  async function cancelMission(mission, context) {
    const currentTime = context.now();
    if (!canCancel(mission, currentTime)) {
      context.toast('O prazo de cancelamento terminou ou o exército já chegou ao alvo.', 'error');
      context.closeModal();
      context.renderGame();
      return false;
    }

    const launchedAt = launchAt(mission);
    const outboundDuration = Math.max(1, number(mission.travelMs, number(mission.endAt) - launchedAt));
    const elapsed = clamp(currentTime - launchedAt, 0, outboundDuration);
    const position = currentPosition(mission, currentTime);
    const returnMs = Math.max(1000, Math.round(elapsed));

    mission.launchStartedAt = launchedAt;
    mission.originalTravelMs = outboundDuration;
    mission.originalArrivalAt = number(mission.endAt);
    mission.cancelWindowEndsAt = cancelUntil(mission);
    mission.cancelled = true;
    mission.cancelledAt = currentTime;
    mission.cancelledTools = toolSnapshot(mission);
    mission.returnOriginPosition = position;
    mission.state = 'returning';
    mission.returning = true;
    mission.win = false;
    mission.loot = { wood: 0, stone: 0, food: 0, coins: 0 };
    mission.startedAt = currentTime;
    mission.endAt = currentTime + returnMs;
    mission.returnStartedAt = currentTime;
    mission.returnEndAt = mission.endAt;
    mission.returnTravelMs = returnMs;

    const profile = context.getProfile();
    profile.reports.push({
      id: context.uid('r'),
      at: currentTime,
      title: `Ataque cancelado: ${mission.targetName}`,
      result: 'info',
      text: `A ordem foi cancelada dentro do prazo permitido. O exército regressa ao castelo e chegará dentro de ${context.formatTime(returnMs)}.`
    });

    context.closeModal();
    context.renderGame();
    context.toast(`Ataque a ${mission.targetName} cancelado. O exército iniciou o regresso.`, 'success');
    await context.persist(true);
    return true;
  }

  function completeReturningMission(context, mission) {
    if (!mission?.cancelled) return false;
    const profile = context.getProfile();

    Object.entries(mission.troops || {}).forEach(([type, count]) => {
      profile.troops[type] = (number(profile.troops[type]) || 0) + Math.max(0, Math.floor(number(count)));
    });

    globalThis.ReinosSiegeTools?.ensureState?.(profile);
    const tools = globalThis.ReinosSiegeTools?.normalizeToolMap?.(mission.cancelledTools || toolSnapshot(mission)) || {};
    Object.entries(tools).forEach(([type, count]) => {
      profile.siegeTools[type] = (number(profile.siegeTools[type]) || 0) + Math.max(0, Math.floor(number(count)));
    });

    mission.state = 'done';
    mission.finishedAt = context.now();
    const troopCount = totalTroops(mission.troops);
    const toolsCount = toolTotal(tools);
    profile.reports.push({
      id: context.uid('r'),
      at: context.now(),
      title: `Exército regressou após cancelamento`,
      result: 'info',
      text: `Regressaram ${context.format(troopCount)} unidade(s) e ${context.format(toolsCount)} ferramenta(s) do ataque cancelado a ${mission.targetName}.`
    });
    context.toast(`O exército do ataque cancelado a ${mission.targetName} regressou ao castelo.`, 'success');
    return true;
  }

  function updateUi(context) {
    const currentTime = context.now();
    document.querySelectorAll('[data-cancel-window]').forEach(element => {
      const mission = findMission(context, element.dataset.cancelWindow);
      if (!mission || !canCancel(mission, currentTime)) {
        element.textContent = 'Prazo terminado';
        const container = element.closest('.queue-item');
        const button = container?.querySelector('[data-action="mission-cancel"]');
        if (button) {
          button.disabled = true;
          button.textContent = 'Não é possível cancelar';
        }
        return;
      }
      element.textContent = context.formatTime(Math.max(0, cancelUntil(mission) - currentTime));
    });
  }

  async function handleAction(action, element, context) {
    if (!['mission-open', 'mission-cancel', 'mission-cancel-confirm'].includes(action)) return false;
    const mission = findMission(context, element.dataset.id);
    if (!mission) {
      context.toast('Esta marcha já terminou.', 'error');
      context.closeModal();
      context.renderGame();
      return true;
    }
    if (mission.type === 'market_transport') return false;
    if (action === 'mission-open') openMission(mission, context);
    if (action === 'mission-cancel') openCancelConfirmation(mission, context);
    if (action === 'mission-cancel-confirm') await cancelMission(mission, context);
    return true;
  }

  globalThis.ReinosAttackCancellation = Object.freeze({
    VERSION,
    CANCEL_WINDOW_MS,
    canCancel,
    cancelUntil,
    currentPosition,
    missionQueueControls,
    completeReturningMission,
    updateUi,
    handleAction
  });
})();
