/**
 * MGT2 Commerce – CommerceDialog
 *
 * Boîte de dialogue principale (ApplicationV2 FoundryVTT).
 * Trois onglets : Passagers / Cargaison / Commerce spéculatif.
 * Les résultats sont postés dans le chat.
 */

import { calculatePassengers, calculateCargo, findAvailableGoods, calculatePrice, formatCredits } from './tradeHelper.js';
import { searchWorlds, fetchWorldDetail, fetchWorldCoordinates, calcParsecs } from './travellerMapApi.js';
import { buildActiveActorContext, COMMERCE_SKILLS, getActiveTravellerActor, rollActorSkillEffect, getActorSkillSummary } from './mgt2eSkills.js';

const { ApplicationV2, HandlebarsApplicationMixin } = foundry.applications.api;
const MODULE_ID = 'mgt2-compendium-amiral-denisov';

export class CommerceDialog extends HandlebarsApplicationMixin(ApplicationV2) {
  static DEFAULT_OPTIONS = {
    id: 'mgt2-commerce',
    classes: ['mgt2-commerce-dialog'],
    position: {
      width: 780,
      height: 'auto',
    },
    window: {
      title: 'Commerce – MgT2e',
      resizable: true,
    },
  };

  static PARTS = {
    main: {
      template: `modules/${MODULE_ID}/templates/commerce-dialog.hbs`,
      root: true,
    },
  };

  constructor(options = {}) {
    super(options);
    this._activeTab = options.initialTab ?? 'passengers';
    this._formData = {
      pax: {
        uwpDep: '', uwpDest: '', zoneDep: 'normal', zoneDest: 'normal',
        parsecs: 1, skillEffect: 0, stewardLevel: 0,
      },
      cargo: {
        uwpDep: '', uwpDest: '', zoneDep: 'normal', zoneDest: 'normal',
        parsecs: 1, skillEffect: 0, navyRank: 0, scoutRank: 0, socMod: 0, armed: false,
      },
      trade: {
        uwp: '', zone: 'normal', brokerSkill: 0, previousAttempts: 0, blackMarket: false,
      },
    };
    this._tradeGoods = null;
    this._worldNames = {};

    if (options.defaultWorld) {
      const w = options.defaultWorld;
      this._defaultWorld = w;
      this._worldNames['pax.uwpDep'] = w.name || '';
      this._worldNames['cargo.uwpDep'] = w.name || '';
      this._worldNames['trade.uwp'] = w.name || '';
      if (w.uwp) this._formData.pax.uwpDep = w.uwp;
      if (w.zone) this._formData.pax.zoneDep = w.zone;
      if (w.uwp) this._formData.cargo.uwpDep = w.uwp;
      if (w.zone) this._formData.cargo.zoneDep = w.zone;
      if (w.uwp) this._formData.trade.uwp = w.uwp;
      if (w.zone) this._formData.trade.zone = w.zone;
      this._activeTab = 'trade';
    }
  }

  async _prepareContext() {
    _registerHandlebarsHelpers();
    const ctx = {
      ...this._formData,
      activeActor: buildActiveActorContext(),
      activeTab: this._activeTab,
    };
    if (this._defaultWorld) {
      ctx.defaultWorldName = this._defaultWorld.name;
      ctx.defaultWorldLoc = `${this._defaultWorld.sector || ''} ${this._defaultWorld.hex || ''}`.trim();
    }
    return ctx;
  }

  async _onRender(context, options) {
    await super._onRender(context, options);

    const html = this._getForm();
    if (!html?.length) return;
    html.addClass('mgt2-commerce-form');

    this._applyThemeStyles(html);

    html.find('[data-action="calculate-passengers"]').on('click', async (ev) => {
      ev.preventDefault();
      this._readForm(html);
      await this._handlePassengers();
    });

    html.find('[data-action="calculate-cargo"]').on('click', async (ev) => {
      ev.preventDefault();
      this._readForm(html);
      await this._handleCargo();
    });

    html.find('[data-action="find-goods"]').on('click', async (ev) => {
      ev.preventDefault();
      this._readForm(html);
      await this._handleFindGoods(html);
    });

    html.on('click', '[data-action="calculate-buy-prices"]', async (ev) => {
      ev.preventDefault();
      this._readForm(html);
      await this._handleBuyPrices();
    });

    html.find('[data-action="load-pax-actor"]').on('click', async (ev) => {
      ev.preventDefault();
      this._applyPassengerActorData(html);
    });

    html.find('[data-action="roll-pax-effect"]').on('click', async (ev) => {
      ev.preventDefault();
      await this._rollActorEffectIntoField(html, 'pax.skillEffect', COMMERCE_SKILLS.passengerEffect);
    });

    html.find('[data-action="load-cargo-actor"]').on('click', async (ev) => {
      ev.preventDefault();
      this._applyCargoActorData(html);
    });

    html.find('[data-action="roll-cargo-effect"]').on('click', async (ev) => {
      ev.preventDefault();
      await this._rollActorEffectIntoField(html, 'cargo.skillEffect', COMMERCE_SKILLS.cargoEffect);
    });

    html.find('[data-action="load-trade-actor"]').on('click', async (ev) => {
      ev.preventDefault();
      this._applyTradeActorData(html);
    });

    html.find('.tabs .item').on('click', (ev) => {
      ev.preventDefault();
      this._readForm(html);
      this._activateTab($(ev.currentTarget).data('tab'));
    });

    this._bindWorldSearch(html);

    // Pré-remplir les champs recherche avec le nom du monde
    if (this._defaultWorld?.name) {
      html.find('.world-search-widget[data-role="dep"] .world-search-input, .world-block-full .world-search-input')
        .val(this._defaultWorld.name);
    }

    html.on('click', (ev) => {
      if (!$(ev.target).closest('.world-search-widget').length) {
        html.find('.world-search-results').empty();
      }
    });
  }

  _getForm() {
    return $(this.element).find('.window-content');
  }

  _activateTab(tabId) {
    const html = this._getForm();
    if (!html?.length) return;

    this._activeTab = tabId;
    html.find('.tabs .item').removeClass('active');
    html.find(`.tabs .item[data-tab="${tabId}"]`).addClass('active');
    html.find('.tab-content .tab').removeClass('active');
    html.find(`.tab-content .tab[data-tab="${tabId}"]`).addClass('active');
    this._applyThemeStyles(html);
  }

  _applyThemeStyles(html) {
    html.find('.tabs .item').css({
      color: '#d8c79a',
      'text-shadow': 'none',
      'background-color': '',
      'border-bottom-color': 'transparent'
    });

    html.find('.tabs .item.active').css({
      color: '#d9b24c',
      'text-shadow': 'none',
      'background-color': 'rgba(201, 162, 39, 0.18)',
      'border-bottom-color': '#c9a227'
    });

    html.find('h3').css({
      color: '#5f4300',
      'border-bottom-color': '#b78f26',
      'text-shadow': 'none'
    });

    html.find('legend').css({
      color: '#7a5c00',
      'text-shadow': 'none'
    });
  }

  _bindWorldSearch(html) {
    html.find('.world-search-widget').each((_, widget) => {
      const $widget = $(widget);
      const $input = $widget.find('.world-search-input');
      const $btn = $widget.find('.btn-world-search');
      const $results = $widget.find('.world-search-results');
      const uwpTarget = $widget.data('uwp-target');
      const zoneTarget = $widget.data('zone-target');
      const parsecsTarget = $widget.data('parsecs-target') || null;
      const role = $widget.data('role') || null;

      const doSearch = async () => {
        const query = $input.val().trim();
        if (query.length < 2) return;
        $btn.prop('disabled', true).html('<i class="fas fa-spinner fa-spin"></i>');
        $results.empty();
        try {
          const worlds = await searchWorlds(query);
          if (!worlds.length) {
            $results.append('<li class="no-result">Aucun monde trouvé</li>');
          } else {
            worlds.slice(0, 10).forEach((w) => {
              const $li = $(`<li data-sector="${w.sector}" data-hex="${w.hex}"><span class="world-name">${w.name}</span> <span class="world-uwp">${w.uwp}</span> <span class="world-sector">${w.sector}</span></li>`);
              $li.on('click', async () => {
                $results.empty();
                $input.val(w.name);
                if (uwpTarget) this._worldNames[uwpTarget] = w.name;
                const [detail, coords] = await Promise.all([
                  fetchWorldDetail(w.sector, w.hex).catch(() => null),
                  fetchWorldCoordinates(w.sector, w.hex).catch(() => null),
                ]);

                const resolvedUwp = detail ? detail.uwp : w.uwp;
                const resolvedZone = detail ? detail.zone : 'normal';

                html.find(`[name="${uwpTarget}"]`).val(resolvedUwp);
                html.find(`[name="${zoneTarget}"]`).val(resolvedZone);
                $widget.data('coords', coords);

                if (uwpTarget === 'pax.uwpDep') {
                  const $cargoDep = html.find('.world-search-widget[data-uwp-target="cargo.uwpDep"]');
                  $cargoDep.find('.world-search-input').val(w.name);
                  html.find('[name="cargo.uwpDep"]').val(resolvedUwp);
                  html.find('[name="cargo.zoneDep"]').val(resolvedZone);
                  $cargoDep.data('coords', coords);
                  this._worldNames['cargo.uwpDep'] = w.name;

                  const $tradeWorld = html.find('.world-search-widget[data-uwp-target="trade.uwp"]');
                  $tradeWorld.find('.world-search-input').val(w.name);
                  html.find('[name="trade.uwp"]').val(resolvedUwp);
                  html.find('[name="trade.zone"]').val(resolvedZone);
                  this._worldNames['trade.uwp'] = w.name;
                }

                if (parsecsTarget) {
                  const partnerRole = role === 'dep' ? 'dest' : 'dep';
                  const $partner = html.find(`.world-search-widget[data-parsecs-target="${parsecsTarget}"][data-role="${partnerRole}"]`);
                  const partnerCoords = $partner.data('coords');
                  if (coords && partnerCoords) {
                    const dist = calcParsecs(coords, partnerCoords);
                    html.find(`[name="${parsecsTarget}"]`).val(dist);
                  }
                }

                this._readForm(html);
              });
              $results.append($li);
            });
          }
        } catch (_err) {
          $results.append('<li class="no-result">Erreur de connexion à Traveller Map</li>');
        }
        $btn.prop('disabled', false).html('<i class="fas fa-globe"></i> Chercher');
      };

      $btn.on('click', doSearch);
      $input.on('keydown', (ev) => {
        if (ev.key === 'Enter') {
          ev.preventDefault();
          doSearch();
        }
      });
    });
  }

  _readForm(html) {
    this._formData.pax.uwpDep = html.find('[name="pax.uwpDep"]').val();
    this._formData.pax.uwpDest = html.find('[name="pax.uwpDest"]').val();
    this._formData.pax.zoneDep = html.find('[name="pax.zoneDep"]').val();
    this._formData.pax.zoneDest = html.find('[name="pax.zoneDest"]').val();
    this._formData.pax.parsecs = parseInt(html.find('[name="pax.parsecs"]').val(), 10) || 1;
    this._formData.pax.skillEffect = parseInt(html.find('[name="pax.skillEffect"]').val(), 10) || 0;
    this._formData.pax.stewardLevel = parseInt(html.find('[name="pax.stewardLevel"]').val(), 10) || 0;

    this._formData.cargo.uwpDep = html.find('[name="cargo.uwpDep"]').val();
    this._formData.cargo.uwpDest = html.find('[name="cargo.uwpDest"]').val();
    this._formData.cargo.zoneDep = html.find('[name="cargo.zoneDep"]').val();
    this._formData.cargo.zoneDest = html.find('[name="cargo.zoneDest"]').val();
    this._formData.cargo.parsecs = parseInt(html.find('[name="cargo.parsecs"]').val(), 10) || 1;
    this._formData.cargo.skillEffect = parseInt(html.find('[name="cargo.skillEffect"]').val(), 10) || 0;
    this._formData.cargo.navyRank = parseInt(html.find('[name="cargo.navyRank"]').val(), 10) || 0;
    this._formData.cargo.scoutRank = parseInt(html.find('[name="cargo.scoutRank"]').val(), 10) || 0;
    this._formData.cargo.socMod = parseInt(html.find('[name="cargo.socMod"]').val(), 10) || 0;
    this._formData.cargo.armed = html.find('[name="cargo.armed"]').is(':checked');

    this._formData.trade.uwp = html.find('[name="trade.uwp"]').val();
    this._formData.trade.zone = html.find('[name="trade.zone"]').val();
    this._formData.trade.brokerSkill = parseInt(html.find('[name="trade.brokerSkill"]').val(), 10) || 0;
    this._formData.trade.previousAttempts = parseInt(html.find('[name="trade.previousAttempts"]').val(), 10) || 0;
    this._formData.trade.blackMarket = html.find('[name="trade.blackMarket"]').is(':checked');
  }

  _getActiveActorOrWarn() {
    const { actor } = getActiveTravellerActor();
    if (!actor) {
      ui.notifications.warn('Aucun token sélectionné ni personnage assigné pour lire les compétences mgt2e.');
      return null;
    }
    return actor;
  }

  _applyPassengerActorData(html) {
    const actor = this._getActiveActorOrWarn();
    if (!actor) return;

    const steward = getActorSkillSummary(actor, COMMERCE_SKILLS.steward);
    this._setNumericSelectValue(html, 'pax.stewardLevel', steward.value);
    this._readForm(html);
    ui.notifications.info(`${actor.name} : Intendant ${steward.value} chargé dans le calcul passagers.`);
  }

  _applyCargoActorData(html) {
    const actor = this._getActiveActorOrWarn();
    if (!actor) return;

    const socMod = Number(actor.system.characteristics?.SOC?.dm ?? 0);
    this._setNumericSelectValue(html, 'cargo.socMod', socMod);
    this._readForm(html);
    ui.notifications.info(`${actor.name} : DM SOC ${socMod >= 0 ? '+' : ''}${socMod} chargé dans le calcul cargaison.`);
  }

  _applyTradeActorData(html) {
    const actor = this._getActiveActorOrWarn();
    if (!actor) return;

    const broker = getActorSkillSummary(actor, COMMERCE_SKILLS.tradeBroker);
    this._setNumericSelectValue(html, 'trade.brokerSkill', broker.value);
    this._readForm(html);
    ui.notifications.info(`${actor.name} : Courtier ${broker.value} chargé pour le commerce spéculatif.`);
  }

  async _rollActorEffectIntoField(html, fieldName, skillList) {
    const actor = this._getActiveActorOrWarn();
    if (!actor) return;

    const rollResult = await rollActorSkillEffect(actor, skillList);
    if (!rollResult) {
      ui.notifications.warn(`${actor.name} ne possède aucune des compétences attendues pour ce calcul.`);
      return;
    }

    this._setNumericSelectValue(html, fieldName, rollResult.effect);
    this._readForm(html);
    ui.notifications.info(`${actor.name} : ${rollResult.label} → 2D6 (${rollResult.diceTotal}) + ${rollResult.totalModifier >= 0 ? '+' : ''}${rollResult.totalModifier} = ${rollResult.total}, effet ${rollResult.effect >= 0 ? '+' : ''}${rollResult.effect}.`);
  }

  _setNumericSelectValue(html, fieldName, value) {
    const select = html.find(`[name="${fieldName}"]`);
    if (!select.length) return;

    const normalized = Number(value ?? 0);
    if (!select.find(`option[value="${normalized}"]`).length) {
      const label = normalized > 0 ? `+${normalized}` : `${normalized}`;
      select.append(`<option value="${normalized}">${label}</option>`);
    }
    select.val(`${normalized}`);
  }

  async _handlePassengers() {
    const p = this._formData.pax;
    if (!p.uwpDep || !p.uwpDest) {
      return ui.notifications.warn('Veuillez saisir les UWP de départ et de destination.');
    }

    const result = await calculatePassengers({
      uwpDep: p.uwpDep,
      uwpDest: p.uwpDest,
      zoneDep: p.zoneDep,
      zoneDest: p.zoneDest,
      parsecs: p.parsecs,
      skillEffect: p.skillEffect,
      stewardLevel: p.stewardLevel,
    });

    if (!result.success) return ui.notifications.error(result.errors.join(' | '));
    result.dep = { ...result.dep, name: this._worldNames['pax.uwpDep'] || '' };
    result.dest = { ...result.dest, name: this._worldNames['pax.uwpDest'] || '' };
    await this._postToChatResult(result);
  }

  async _handleCargo() {
    const c = this._formData.cargo;
    if (!c.uwpDep || !c.uwpDest) {
      return ui.notifications.warn('Veuillez saisir les UWP de départ et de destination.');
    }

    const result = await calculateCargo({
      uwpDep: c.uwpDep,
      uwpDest: c.uwpDest,
      zoneDep: c.zoneDep,
      zoneDest: c.zoneDest,
      parsecs: c.parsecs,
      skillEffect: c.skillEffect,
      navyRank: c.navyRank,
      scoutRank: c.scoutRank,
      socMod: c.socMod,
      armed: c.armed,
    });

    if (!result.success) return ui.notifications.error(result.errors.join(' | '));
    result.cargoRevenue = result.lots.reduce((s, l) => s + l.revenue, 0);
    result.dep = { ...result.dep, name: this._worldNames['cargo.uwpDep'] || '' };
    result.dest = { ...result.dest, name: this._worldNames['cargo.uwpDest'] || '' };
    await this._postToChatResult(result);
  }

  async _handleFindGoods(html) {
    const t = this._formData.trade;
    if (!t.uwp) {
      return ui.notifications.warn('Veuillez saisir le code UWP du monde.');
    }

    const result = await findAvailableGoods({
      uwp: t.uwp,
      zone: t.zone,
      blackMarket: t.blackMarket,
      brokerSkill: t.brokerSkill,
      previousAttempts: t.previousAttempts,
    });

    if (!result.success) return ui.notifications.error(result.errors.join(' | '));

    result.world = { ...result.world, name: this._worldNames['trade.uwp'] || '' };
    this._tradeGoods = result;
    const goodsDiv = html.find('.trade-goods-result');
    const listDiv = html.find('.trade-goods-list');

    if (result.goods.length === 0) {
      listDiv.html('<p><em>Aucune marchandise disponible sur ce monde.</em></p>');
    } else {
      const rows = result.goods.map((g) => `
        <div class="trade-good-item">
          <label>
            <input type="checkbox" class="good-select" data-d66="${g.d66}" checked>
            <strong>[${g.d66}] ${g.name}</strong>
            — ${g.tons} t — ${formatCredits(g.basePrice)}/t
            (achat MD ${g.buyMod >= 0 ? '+' : ''}${g.buyMod},
             vente MD ${g.sellMod >= 0 ? '+' : ''}${g.sellMod})
          </label>
        </div>
      `).join('');
      listDiv.html(rows);
    }

    goodsDiv.show();
    await this._postToChatResult(result);
  }

  async _handleBuyPrices() {
    if (!this._tradeGoods || !this._tradeGoods.goods.length) {
      return ui.notifications.warn('Veuillez d\'abord trouver les marchandises disponibles.');
    }

    const brokerSkill = this._formData.trade.brokerSkill;
    const prices = [];
    for (const g of this._tradeGoods.goods) {
      const priceResult = await calculatePrice({
        basePrice: g.basePrice,
        buyMod: g.buyMod,
        sellMod: g.sellMod,
        brokerSkill,
        mode: 'buy',
      });
      prices.push({
        name: g.name,
        tons: g.tons,
        basePrice: g.basePrice,
        diceResult: priceResult.diceResult,
        modifier: priceResult.modifier,
        total: priceResult.total,
        percent: priceResult.percent,
        actualPrice: priceResult.actualPrice,
        totalCost: priceResult.actualPrice * g.tons,
      });
    }

    const grandTotal = prices.reduce((s, p) => s + p.totalCost, 0);
    await this._postToChatResult({ type: 'buy-prices', prices, grandTotal });
  }

  async _postToChatResult(data) {
    _registerHandlebarsHelpers();
    const html = await foundry.applications.handlebars.renderTemplate(`modules/${MODULE_ID}/templates/commerce-result.hbs`, data);
    await ChatMessage.create({
      content: html,
      speaker: ChatMessage.getSpeaker(),
      flags: { [MODULE_ID]: { type: 'commerce-result' } },
    });
  }
}

let _helpersRegistered = false;

function _registerHandlebarsHelpers() {
  if (_helpersRegistered) return;
  _helpersRegistered = true;

  Handlebars.registerHelper('formatCredits', (amount) => formatCredits(amount));
  Handlebars.registerHelper('join', (arr, sep) => (Array.isArray(arr) ? arr.join(sep) : ''));
  Handlebars.registerHelper('gt', (a, b) => a > b);
  Handlebars.registerHelper('gte', (a, b) => a >= b);
  Handlebars.registerHelper('eq', (a, b) => a === b);
  Handlebars.registerHelper('modClass', (n) => (Number(n) > 0 ? 'mod-pos' : Number(n) < 0 ? 'mod-neg' : 'mod-zero'));
  Handlebars.registerHelper('modSelect', function(id, name, value, min, max) {
    let opts = '';
    for (let i = min; i <= max; i++) {
      const label = i > 0 ? `+${i}` : `${i}`;
      const sel = value === i ? ' selected' : '';
      opts += `<option value="${i}"${sel}>${label}</option>`;
    }
    return new Handlebars.SafeString(`<select id="${id}" name="${name}">${opts}</select>`);
  });
}
