// assets/js/execvitr.js
(function(){
  // ===== SETTINGS =====
  var settings = window.execvitrData || window.ExecvitrData || window.CityCourierData || {};
  if (!settings || Object.keys(settings).length === 0) {
    console.warn('[execvitr] pricing settings not found on window (execvitrData/ExecvitrData).');
    settings = {};
  }

  
  // ===== MIN ADVANCE BOOKING (hours) =====
  var leadHours = parseInt(settings.min_booking_hours || 0, 10);
  if (!isFinite(leadHours) || leadHours < 0) leadHours = 0;

  function pad2(n){ n = parseInt(n,10); return (n<10?'0':'') + n; }
  function fmtDate(d){
    return d.getFullYear() + '-' + pad2(d.getMonth()+1) + '-' + pad2(d.getDate());
  }
  function fmtTime(d){
    return pad2(d.getHours()) + ':' + pad2(d.getMinutes());
  }
  function roundUpTo30Min(d){
    var dd = new Date(d.getTime());
    dd.setSeconds(0); dd.setMilliseconds(0);
    var m = dd.getMinutes();
    var add = (m % 30 === 0) ? 0 : (30 - (m % 30));
    dd.setMinutes(m + add);
    return dd;
  }
  function getLeadMinDateTime(){
    if (!leadHours) return null;
    return roundUpTo30Min(new Date(Date.now() + leadHours * 60 * 60 * 1000));
  }
  function getFormField(form, selector){
    return form ? form.querySelector(selector) : document.querySelector(selector);
  }
  function rebuildTimeSlots(form, minTime){
    var timeEl = getFormField(form, "[name='pickup_time']");
    var listId = timeEl && timeEl.getAttribute('list') ? timeEl.getAttribute('list') : 'time_slots';
    var dl = document.getElementById(listId);
    if (!dl) return;
    dl.innerHTML = '';
    var startH = 0, startM = 0;
    if (minTime && /^\d{2}:\d{2}$/.test(minTime)){
      startH = parseInt(minTime.slice(0,2),10);
      startM = parseInt(minTime.slice(3,5),10);
    }
    for (var h=0; h<24; h++){
      for (var mm=0; mm<=30; mm+=30){
        if (h < startH) continue;
        if (h === startH && mm < startM) continue;
        var opt = document.createElement('option');
        opt.value = pad2(h) + ':' + pad2(mm);
        dl.appendChild(opt);
      }
    }
  }
  function applyLeadTimeConstraints(form){
    if (!leadHours) return;
    var dateEl = getFormField(form, "[name='pickup_date']");
    var timeEl = getFormField(form, "[name='pickup_time']");
    if (!dateEl || !timeEl) return;

    var minDT = getLeadMinDateTime();
    if (!minDT) return;

    var minDate = fmtDate(minDT);
    var minTime = fmtTime(minDT);

    // enforce min date
    try { dateEl.min = minDate; } catch(e){}

    // default values if empty
    if (!dateEl.value) dateEl.value = minDate;

    // if date is before minDate, snap
    if (dateEl.value && dateEl.value < minDate) dateEl.value = minDate;

    // min time depends on selected date
    var selectedDate = dateEl.value;
    var activeMinTime = (selectedDate === minDate) ? minTime : '00:00';
    try { timeEl.min = activeMinTime; } catch(e){}

    rebuildTimeSlots(form, activeMinTime);

    // default time if empty or too early
    if (!timeEl.value) timeEl.value = activeMinTime;
    if (timeEl.value && timeEl.value < activeMinTime) timeEl.value = activeMinTime;
  }

  function setDefaultReturnDateTime(form){
    var pickupDate = getFormField(form, 'input[name="pickup_date"]');
    var pickupTime = getFormField(form, 'input[name="pickup_time"]');
    var returnDate = getFormField(form, 'input[name="return_date"]');
    var returnTime = getFormField(form, 'input[name="return_time"]');
    if (!returnDate || !returnTime) return;

    var baseDate = pickupDate && pickupDate.value ? new Date(pickupDate.value + 'T00:00:00') : new Date();
    if (isNaN(baseDate.getTime())) baseDate = new Date();
    var nextDay = new Date(baseDate.getTime());
    nextDay.setDate(nextDay.getDate() + 1);

    if (!returnDate.value) returnDate.value = fmtDate(nextDay);
    if (!returnTime.value) returnTime.value = (pickupTime && pickupTime.value) ? pickupTime.value : '09:00';
  }

  function syncReturnFields(form){
    var cb = getFormField(form, '[name="is_return"]');
    var box = form ? form.querySelector('.execvitr-return-datetime') : document.getElementById('execvitr_return_fields');
    if (!cb || !box) return;
    box.style.display = cb.checked ? 'grid' : 'none';
    var returnDate = getFormField(form, 'input[name="return_date"]');
    var returnTime = getFormField(form, 'input[name="return_time"]');
    if (returnDate) returnDate.required = !!cb.checked;
    if (returnTime) returnTime.required = !!cb.checked;
    if (cb.checked) setDefaultReturnDateTime(form);
    if (typeof window.tryUpdatePrice === 'function') window.tryUpdatePrice(form || null);
  }

  function initExecvitrForm(form){
    if (!form || form.dataset.execvitrReady === '1') return;
    form.dataset.execvitrReady = '1';

    var cb = getFormField(form, '[name="is_return"]');
    if (cb) cb.addEventListener('change', function(){ syncReturnFields(form); });
    syncReturnFields(form);

    applyLeadTimeConstraints(form);

    var dateEl = getFormField(form, "[name='pickup_date']");
    var timeEl = getFormField(form, "[name='pickup_time']");
    if (dateEl) dateEl.addEventListener('change', function(){ applyLeadTimeConstraints(form); setDefaultReturnDateTime(form); });
    if (timeEl) timeEl.addEventListener('change', function(){ applyLeadTimeConstraints(form); setDefaultReturnDateTime(form); });

    try {
      var checked = form.querySelector('input[name="car_choice"]:checked');
      if (!checked) {
        var first = form.querySelector('input[name="car_choice"]');
        if (first) {
          first.checked = true;
          first.dispatchEvent(new Event('change', { bubbles: true }));
        }
      }
    } catch(e){}

    form.addEventListener('submit', function(e){
      if (!leadHours) return;
      var minDT = getLeadMinDateTime();
      if (!minDT) return;
      var dateEl = getFormField(form, "[name='pickup_date']");
      var timeEl = getFormField(form, "[name='pickup_time']");
      if (!dateEl || !timeEl || !dateEl.value || !timeEl.value) return;
      var selected = new Date(dateEl.value + 'T' + timeEl.value + ':00');
      if (isNaN(selected.getTime())) return;
      if (selected.getTime() < minDT.getTime()) {
        e.preventDefault();
        alert('Please select a pickup time at least ' + leadHours + ' hours from now.');
        applyLeadTimeConstraints(form);
      }
    }, true);
  }

  document.addEventListener('DOMContentLoaded', function(){
    var forms = document.querySelectorAll('form.vts-form, form.execvitr-transfer-form, form[data-execvitr-form="1"]');
    if (!forms.length) {
      var single = document.querySelector('form#vts-form') || document.querySelector('form[action*="execvitr"]');
      if (single) forms = [single];
    }
    Array.prototype.forEach.call(forms, initExecvitrForm);

    document.querySelectorAll('input[type="date"], input[type="time"]').forEach(function(input){
      input.addEventListener('click', function(){ if (input.showPicker) input.showPicker(); });
    });
  });
// Wait for Google Maps SDK if not ready yet (prevents double-load and race conditions)
  try {
    if (!(window.google && google.maps && google.maps.places)) {
      document.addEventListener('execvitr:gmaps-ready', function(){
        try { if (typeof window.tryUpdatePrice === 'function') { window.tryUpdatePrice(); } } catch(e){}
      }, { once: true });
    }
  } catch(e){}

function hasCars() {
  // PHP'den gelen bayrak öncelikli
  if (typeof settings.has_cars !== 'undefined') {
    return !!settings.has_cars;
  }
  // fallback (teorik olarak)
  return !!document.querySelector('.vts-car-card input[name="car_choice"]');
}

function isPro() {
  if (typeof settings.is_pro !== 'undefined') return !!settings.is_pro;
  // fallback: eğer kartlarda kmprice varsa pro say
  var any = false;
  document.querySelectorAll('.vts-car-card input[name="car_choice"]').forEach(function(r){
    var rate = parseFloat((r && r.dataset && r.dataset.kmprice) ? r.dataset.kmprice : '0') || 0;
    if (rate > 0) any = true;
  });
  return any;
}

  function pricingMode() {
    return settings.pricing_mode || (isPro() ? 'pro' : 'free');
  }

	// ===== SUMMARY METRICS (Distance / Duration) =====
function setSummaryMetrics(distanceText, durationText){
  var dEl = document.getElementById('metric-distance');
  var tEl = document.getElementById('metric-duration');
  if (dEl) dEl.textContent = distanceText || '—';
  if (tEl) tEl.textContent = durationText || '—';

  try {
    document.dispatchEvent(new CustomEvent('execvitr:metrics-updated', {
      detail: { distance: distanceText || null, duration: durationText || null }
    }));
  } catch(e){}
}
function clearSummaryMetrics(){ setSummaryMetrics('—','—'); }

(function () {
  function normalizePhone(raw) {
    return String(raw || "").replace(/[^\d]/g, "");
  }

  function buildE164() {
    var form = document.querySelector('form.vts-form, form.execvitr-transfer-form, form[data-execvitr-form="1"]');
    var dialSel = form ? form.querySelector('select[name="dial_code"]') : document.querySelector('select[name="dial_code"]');
    var phoneInp = form ? form.querySelector('input[name="pickup_phone"]') : document.querySelector('input[name="pickup_phone"]');
    var e164Inp  = form ? form.querySelector('input[name="pickup_phone_e164"]') : document.querySelector('input[name="pickup_phone_e164"]');
    if (!dialSel || !phoneInp || !e164Inp) return;

    var dial = normalizePhone(dialSel.value);
    var num  = normalizePhone(phoneInp.value);

    // Baştaki 0'ları kırp (TR vb. için genelde iyi olur)
    num = num.replace(/^0+/, "");

    e164Inp.value = dial && num ? ("+" + dial + num) : "";
  }

  document.addEventListener("change", function (e) {
    if (e.target && e.target.matches('select[name="dial_code"]')) buildE164();
  });

  document.addEventListener("input", function (e) {
    if (e.target && e.target.name === "pickup_phone") buildE164();
  });

  document.addEventListener("submit", function (e) {
    var form = e.target;
    if (!form || form.id !== "vts-form") return;
    buildE164();
  }, true);
})();

  // ===== MONEY / DISPLAY HELPERS =====
  function currency(){ return settings.currency_symbol || settings.currency_code || '$'; }
  function minPrice(){ return Number(settings.minimum_price || 0) || 0; }
  function baseKmPrice(){ return Number(settings.km_price || 0) || 0; }
  function maxDistanceKm(){ return Number(settings.max_distance_km || 0) || 0; }

  // Distance unit helpers (pricing uses selected unit rate)
  function distanceUnit(){
    return (settings.distance_unit === 'mi') ? 'mi' : 'km';
  }
  function kmToSelectedUnit(km){
    km = Number(km || 0) || 0;
    return distanceUnit() === 'mi' ? (km / 1.609344) : km;
  }

  function formatMoney(n, symbol) {
    var val = Number.isFinite(n) ? n : parseFloat(n || 0) || 0;
    var s   = symbol || currency();
    try { return s + ' ' + Number(val).toLocaleString(undefined, { minimumFractionDigits: 2, maximumFractionDigits: 2 }); }
    catch(e){ return s + ' ' + (Math.round(val * 100) / 100).toFixed(2); }
  }
  function placeholderMoney(){ return (currency() + ' —'); }

	function selectedCarEl() {
  return document.querySelector('input[name="car_choice"]:checked');
}

function canShowTotal(kmVal) {
  // hiç araba yoksa (free mod gibi) => her zaman gösterebiliriz
  if (!hasCars()) return true;

  // araba varsa => ancak araç seçildiyse göster
  if (selectedCarEl()) return true;

  // araç yok seçilmemiş -> gizle
  return false;
}


function setTotalDisplay(total, note) {
    var amountEl = document.querySelector(".dv-order-total-price__value .total-amount");
    var noteEl   = document.getElementById('vts-brand-note') || document.querySelector('.brand-note');
    var hidden   = document.getElementById("total_price");

    if (!canShowTotal(/*kmVal not needed here*/)) {
        // Araç seçilmeden gösterme
        if (amountEl) amountEl.textContent = currency() + ' —';
        if (noteEl)   noteEl.textContent   = '';
        if (hidden)   hidden.value         = '';
        return;
    }

    if (amountEl) amountEl.textContent = formatMoney(total);
    if (noteEl)   noteEl.textContent   = note || '';
    if (hidden)   hidden.value         = total;
}

function clearTotalDisplay(){
    var amountEl = document.querySelector(".dv-order-total-price__value .total-amount");
    var noteEl   = document.getElementById('vts-brand-note') || document.querySelector('.brand-note');
    var hidden   = document.getElementById("total_price");

    // clear her zaman placeholder
    if (amountEl) amountEl.textContent = currency() + ' —';
    if (noteEl)   noteEl.textContent   = '';
    if (hidden)   hidden.value         = '';
}


  function setDistanceWarning(km) {
    var limit = maxDistanceKm();
    var warnEl = document.querySelector(".distance-warning") || document.getElementById('vts-distance-warning');
    var submitBtn = document.querySelector("#vts-form .form-submit-btn");
    if (!warnEl || !submitBtn) return;

    if (limit > 0 && km > limit) {
      warnEl.textContent =
        (settings.country ? "[" + String(settings.country).toUpperCase() + "] " : "") +
        "Maximum distance (" + limit + " km) exceeded. Please choose a shorter route.";
      warnEl.classList.add("vts-warning");
      submitBtn.disabled = true;
    } else {
      warnEl.textContent = "";
      warnEl.classList.remove("vts-warning");
      submitBtn.disabled = false;
    }
  }

  // ===== PRICING CORE =====
function selectedCarKmPrice() {
  var el = selectedCarEl();
  var v  = (el && el.dataset && el.dataset.kmprice) ? parseFloat(el.dataset.kmprice) : 0;
  return Number.isFinite(v) ? v : 0;
}

// burada davranışı değiştiriyoruz:
function effectiveKmPrice() {
  // Eğer araba listesi varsa:
  if (hasCars()) {
    // Araç seçiliyse onun km fiyatı
    var car = selectedCarKmPrice();
    if (car > 0) return car;

    // Araç seçili değilse total hesaplamada fallback global kullanmak istemiyoruz
    // çünkü biz total'i zaten göstermiyoruz (setTotalDisplay engelliyor)
    // ama yine de döndürmemiz lazım ki matematik patlamasın.
    // Globali döndürsek de sorun yok çünkü ekranda gösterilmeyecek.
    return baseKmPrice();
  }

  // Araç yoksa (free mode gibi) global km fiyatı geçerli
  return baseKmPrice();
}

  
  function returnMultiplier(){
    try{
      var cb = document.getElementById('execvitr_is_return');
      return (cb && cb.checked) ? 2 : 1;
    }catch(e){ return 1; }
  }

  function priceFromKm(km) {
    var unitDist = kmToSelectedUnit(km);
    var p = Math.max(minPrice(), (Number(unitDist||0) * effectiveKmPrice()));
    p = p * returnMultiplier();
    return Math.round(p * 100) / 100;
  }
  function priceFromKmWithRate(km, kmRate) {
    var unitDist = kmToSelectedUnit(km);
    var p = Math.max(minPrice(), (Number(unitDist||0) * (Number(kmRate)||0)));
    p = p * returnMultiplier();
    return Math.round(p * 100) / 100;
  }

  // ===== CARD PRICES (show after distance only) =====
  function renderCardPricesByKm(km) {
    var cards = document.querySelectorAll('.vts-car-card');
    if (!cards || !cards.length) return;

    var hasKm = Number(km||0) > 0;

    cards.forEach(function(card){
      var radio = card.querySelector('input[name="car_choice"]');
      var outEl = card.querySelector('.vts-car-price-amount');
      if (!outEl) return;

      if (!hasKm) {
        outEl.textContent = placeholderMoney(); // ⬅️ başta boş/placeholder
        return;
      }

      // PRO: araç km; FREE: global km
      var kmRate = baseKmPrice();
      if (isPro() && radio) {
        var carRate = (radio.dataset && radio.dataset.kmprice) ? parseFloat(radio.dataset.kmprice) : 0;
        if (carRate > 0) kmRate = carRate;
      }

      var val = priceFromKmWithRate(km, kmRate);
      outEl.textContent = formatMoney(val);
    });
  }

  // ===== DISTANCE (JS SDK) =====
  
  // ===== PLACE ID SUPPORT (prevents NOT_FOUND / flaky routes) =====
  function getPlaceId(isFrom){
    var el = document.getElementById(isFrom ? 'execvitr_origin_place_id' : 'execvitr_dest_place_id');
    return el && el.value ? String(el.value) : '';
  }
  function clearPlaceId(isFrom){
    var el = document.getElementById(isFrom ? 'execvitr_origin_place_id' : 'execvitr_dest_place_id');
    if (el) el.value = '';
  }
  function originForMaps(){
    var pid = getPlaceId(true);
    if (pid) return { placeId: pid };
    var aEl = document.getElementById('address_from');
    return aEl && aEl.value ? aEl.value.trim() : '';
  }
  function destForMaps(){
    var pid = getPlaceId(false);
    if (pid) return { placeId: pid };
    var bEl = document.getElementById('address_to');
    return bEl && bEl.value ? bEl.value.trim() : '';
  }

var lastMeters = 0;
  var lastFrom = '', lastTo = '';

  function dmAvailable(){
    return (window.google && google.maps && google.maps.DistanceMatrixService);
  }

  function estimateDistanceMeters(origin, destination, cb){
    if (!dmAvailable()) { cb(new Error('maps_not_ready')); return; }
    var svc = new google.maps.DistanceMatrixService();
    svc.getDistanceMatrix({
      origins: [origin],
      destinations: [destination],
      travelMode: google.maps.TravelMode.DRIVING,
      unitSystem: (distanceUnit() === 'mi') ? google.maps.UnitSystem.IMPERIAL : google.maps.UnitSystem.METRIC
    }, function(res, status){
      if (status !== 'OK' || !res || !res.rows || !res.rows[0] || !res.rows[0].elements || !res.rows[0].elements[0]) {
        cb(new Error(status || 'dm_error'));
        return;
      }
      var el = res.rows[0].elements[0];
      if (el.status !== 'OK') { cb(new Error(el.status || 'no_result')); return; }
      cb(null, { meters: el.distance.value, text: el.distance.text, duration: el.duration && el.duration.text });
    });
  }

    function syncDistanceHiddenFields(km, distanceText, durationText){
    var dTextEl = document.getElementById('execvitr-distance-text');
    var dKmEl   = document.getElementById('execvitr-distance-km');
    var durEl   = document.getElementById('execvitr-duration-text');

    if (dTextEl) dTextEl.value = distanceText || '';
    if (dKmEl)   dKmEl.value   = (km && km > 0) ? km.toFixed(3) : '';
    if (durEl)   durEl.value   = durationText || '';
  }

  function setSubmitEnabled(enabled){
    var btn = document.querySelector('#execvitr-submit-btn, button[name="execvitr_submit"], button[type="submit"].execvitr-submit');
    if (!btn) btn = document.querySelector('form.execvitr-form button[type="submit"], form#execvitrForm button[type="submit"]');
    if (!btn) return;
    btn.disabled = !enabled;
    btn.classList.toggle('is-disabled', !enabled);
  }

  function showInlineError(msg){
    var box = document.getElementById('execvitr-inline-error');
    if (!box) {
      box = document.createElement('div');
      box.id = 'execvitr-inline-error';
      box.style.marginTop = '10px';
      box.style.padding = '10px 12px';
      box.style.borderRadius = '10px';
      box.style.fontSize = '14px';
      box.style.border = '1px solid rgba(0,0,0,.12)';
      box.style.background = 'rgba(255,0,0,.05)';
      var form = document.querySelector('form.execvitr-form') || document.getElementById('execvitrForm');
      if (form) form.insertBefore(box, form.firstChild);
    }
    box.textContent = msg || '';
    box.style.display = msg ? 'block' : 'none';
  }



  // Debounce
  var debounceTimer = null;
  function debounce(fn, delay){
    clearTimeout(debounceTimer);
    debounceTimer = setTimeout(fn, delay);
  }

  function recalcDistanceAndPrice(){
    var aEl = document.getElementById('address_from');
    var bEl = document.getElementById('address_to');
    var aTxt = aEl && aEl.value ? aEl.value.trim() : '';
    var bTxt = bEl && bEl.value ? bEl.value.trim() : '';
    var a = originForMaps();
    var b = destForMaps();

    if (!aTxt || !bTxt || aTxt.length < 3 || bTxt.length < 3) {
      lastMeters = 0;
      clearTotalDisplay();    
      setDistanceWarning(0);
      renderCardPricesByKm(0);
      clearSummaryMetrics();
      syncDistanceHiddenFields(0, '', '');
      return;
    }


    if (a === lastFrom && b === lastTo && lastMeters > 0) {
      var kmCached = lastMeters / 1000.0;
	  var u = distanceUnit();
	  var d = kmToSelectedUnit(kmCached);
	  setTotalDisplay(priceFromKm(kmCached), '~ ' + d.toFixed(1) + ' ' + u);
      setDistanceWarning(kmCached);
      renderCardPricesByKm(kmCached);
      return;
    }

    debounce(function(){
      estimateDistanceMeters(a, b, function(err, out){
                if (err) {
          lastMeters = 0;
          clearTotalDisplay();
          setDistanceWarning(0);
          renderCardPricesByKm(0);
          clearSummaryMetrics();
          syncDistanceHiddenFields(0, '', '');
          return;
        }

        lastFrom = a; lastTo = b;
        lastMeters = Number(out.meters||0);
        var km = lastMeters / 1000.0;

        var distanceText = out.text || '—';
        var durationText = out.duration || '—';

        // UI özet
        setSummaryMetrics(distanceText, durationText);
        setTotalDisplay(priceFromKm(km), distanceText ? ('~ ' + distanceText) : '');
        setDistanceWarning(km);
        renderCardPricesByKm(km);

        // 🔥 PHP'ye gidecek hidden input'ları güncelle
        syncDistanceHiddenFields(km, distanceText, durationText);

        setSubmitEnabled(true);
        showInlineError('');

      });
    }, 250);
  }

  // Eski kod uyumluluğu
  if (typeof window.tryUpdatePrice !== 'function') {
    window.tryUpdatePrice = function() {
      if (typeof recalcDistanceAndPrice === 'function') recalcDistanceAndPrice();
    };
  }

  // ===== AUTOCOMPLETE (mapsReadyStart) =====
  function mapsReadyStart() {
    var fromInput = document.getElementById("address_from");
    var toInput   = document.getElementById("address_to");
    if (
      fromInput &&
      toInput &&
      window.google &&
      window.google.maps &&
      window.google.maps.places
    ) {
      var countryCode =
        (settings && settings.country) ? String(settings.country).toUpperCase() : undefined;

      var compRes = countryCode ? { country: countryCode } : undefined;

      var options = {
        // types: ["geocode"],
        ...(compRes ? { componentRestrictions: compRes } : {}),
        componentRestrictions: compRes,
        fields: [ "address_components", "formatted_address", "geometry.location", "place_id" ]
      };

      var fromAutocomplete = new google.maps.places.Autocomplete(fromInput, options);
      var toAutocomplete   = new google.maps.places.Autocomplete(toInput,   options);

      function extractAddressDetails(place) {
        var mahalle = "", ilce = "", sehir = "", postaKodu = "", ulke = "";
        if (!place || !place.address_components) return { mahalle: mahalle, ilce: ilce, sehir: sehir, posta_kodu: postaKodu, ulke: ulke };

        place.address_components.forEach(function(comp){
          var types = comp.types || [];
          if (types.includes("neighborhood") || types.includes("sublocality") || types.includes("sublocality_level_1")) {
            mahalle = comp.long_name;
          }
          if (types.includes("administrative_area_level_2")) {
            ilce = comp.long_name;
          }
          // City: prefer locality/postal_town; fallback to admin_area_level_1
          if (types.includes("locality") || types.includes("postal_town")) {
            sehir = comp.long_name;
          }
          if (types.includes("administrative_area_level_1") && !sehir) {
            sehir = comp.long_name;
          }
          if (types.includes("postal_code")) {
            postaKodu = comp.long_name;
          }
          if (types.includes("country")) {
            ulke = comp.short_name || comp.long_name;
          }
        });
        return { mahalle: mahalle, ilce: ilce, sehir: sehir, posta_kodu: postaKodu, ulke: ulke };
      }

      function applyDetailsToInput(input, place, isPickup) {
        var details   = extractAddressDetails(place);
        var formatted = (place && place.formatted_address) ? place.formatted_address : (input.value || "");
        var mahalleText = details.mahalle ? (" (" + details.mahalle + ")") : "";
        input.value = formatted + mahalleText;
        input.setAttribute("data-mahalle", details.mahalle || "");
        input.setAttribute("data-ilce",    details.ilce    || "");
        input.setAttribute("data-sehir",   details.sehir   || "");
        input.setAttribute("data-postcode", details.posta_kodu || "");
        input.setAttribute("data-country", details.ulke || "");

        // Fill hidden WooCommerce billing fields from PICKUP address
        if (isPickup) {
          var hAddr = document.getElementById('execvitr_billing_address_1');
          var hCity = document.getElementById('execvitr_billing_city');
          var hPost = document.getElementById('execvitr_billing_postcode');
          var hCtry = document.getElementById('execvitr_billing_country');
          if (hAddr) hAddr.value = formatted;
          if (hCity) hCity.value = details.sehir || '';
          if (hPost) hPost.value = details.posta_kodu || '';
          if (hCtry) hCtry.value = (details.ulke || countryCode || '').toUpperCase();
        }
      }

      fromAutocomplete.addListener("place_changed", function () {
        var place = fromAutocomplete.getPlace();
        applyDetailsToInput(fromInput, place, true);
        window.tryUpdatePrice();
      });

      toAutocomplete.addListener("place_changed", function () {
        var place = toAutocomplete.getPlace();
        applyDetailsToInput(toInput, place, false);
        window.tryUpdatePrice();
      });

      fromInput.addEventListener("input", function(){ clearPlaceId(true); });
      fromInput.addEventListener("change", function(){ clearPlaceId(true); window.tryUpdatePrice(); });
      fromInput.addEventListener("blur", function(){ window.tryUpdatePrice(); });
      toInput.addEventListener("input", function(){ clearPlaceId(false); });
      toInput.addEventListener("change", function(){ clearPlaceId(false); window.tryUpdatePrice(); });
      toInput.addEventListener("blur", function(){ window.tryUpdatePrice(); });
    }

    // İlk görünüm: boş/placeholder, min değil
    clearTotalDisplay();
    setDistanceWarning(0);
    renderCardPricesByKm(0);
  }

  // Google hazır olunca başlat
  (function checkGoogleReadyAndInit(){
    if (window.google && google.maps && google.maps.places) {
      mapsReadyStart();
    } else {
      setTimeout(checkGoogleReadyAndInit, 300);
    }
  })();

  // ===== CAR CHANGE (Toplam anında yenilensin; mesafe yoksa yine boş kalsın) =====
document.addEventListener('change', function(e){
  if (e.target && e.target.name === 'car_choice') {
    // --- Capacity limits (passengers / luggage) ---
    try {
      var passEl = document.querySelector('input[name="passenger_count"]');
      var bagEl  = document.querySelector('input[name="luggage_count"]');
      var maxP = parseInt((e.target.dataset && e.target.dataset.passengers) ? e.target.dataset.passengers : '0', 10) || 0;
      var maxB = parseInt((e.target.dataset && e.target.dataset.luggage) ? e.target.dataset.luggage : '0', 10) || 0;
      if (passEl && maxP > 0) {
        passEl.max = String(maxP);
        var curP = parseInt(passEl.value || '0', 10) || 0;
        if (curP > maxP) passEl.value = String(maxP);
        passEl.setAttribute('title', 'Max ' + maxP);
      }
      if (bagEl && maxB >= 0) {
        bagEl.max = String(maxB);
        var curB = parseInt(bagEl.value || '0', 10) || 0;
        if (curB > maxB) bagEl.value = String(maxB);
        bagEl.setAttribute('title', 'Max ' + maxB);
      }
    } catch(err) {}

    // marka notu vs zaten başka yerde güncelleniyor ama biz total'i güncelleyelim
    if (lastMeters > 0) {
      var km = lastMeters / 1000.0;
      // şimdi araç seçildiği için canShowTotal() true olacak
      var u = distanceUnit();
      var d = kmToSelectedUnit(km);
      setTotalDisplay(priceFromKm(km), '~ ' + d.toFixed(1) + ' ' + u);
    } else {
      // mesafe henüz yoksa yine hesaplamayı dene
      recalcDistanceAndPrice();
    }
  }
});

// Enforce capacity limits while typing (clamp to input.max)
document.addEventListener('input', function(e){
  if (!e.target) return;
  if (e.target.name === 'passenger_count' || e.target.name === 'luggage_count') {
    var max = parseInt(e.target.max || '0', 10) || 0;
    if (max > 0) {
      var v = parseInt(e.target.value || '0', 10) || 0;
      if (v > max) e.target.value = String(max);
    }
  }
});

// Enforce max values even if user types manually
document.addEventListener('input', function(e){
  if (!e.target) return;
  if (e.target.name !== 'passenger_count' && e.target.name !== 'luggage_count') return;
  var car = document.querySelector('input[name="car_choice"]:checked');
  if (!car) return;
  var maxP = parseInt((car.dataset && car.dataset.passengers) ? car.dataset.passengers : '0', 10) || 0;
  var maxB = parseInt((car.dataset && car.dataset.luggage) ? car.dataset.luggage : '0', 10) || 0;
  var v = parseInt(e.target.value || '0', 10) || 0;
  if (e.target.name === 'passenger_count' && maxP > 0 && v > maxP) e.target.value = String(maxP);
  if (e.target.name === 'luggage_count' && maxB >= 0 && v > maxB) e.target.value = String(maxB);
});


  // ===== SUMMARY (opsiyonel mevcut UI) =====
  window.fillSummary = function(){
    var summary = document.querySelector(".summary-output");
    if (!summary) return;
    var get = function(sel){ var el = document.querySelector(sel); return el ? el.value : ''; };
    var getChecked = function(name){ var el = document.querySelector("[name='"+name+"']:checked"); return el ? el.value : ''; };
    var date = get("[name='pickup_date']"); var time = get("[name='pickup_time']");
    var arrival = (date && time) ? (date + " " + time) : "";
    var data = {
      address_from:    get("[name='address_from']"),
      address_to:      get("[name='address_to']"),
      sender:          get("[name='sender_name']"),
      sender_surname:  get("[name='sender_surname']"),
      email:           get("[name='user_email']"),
      passenger_count: get("[name='passenger_count']"),
      luggage_count:   get("[name='luggage_count']"),
      arrival_time:    arrival,
      car_choice:      getChecked("car_choice"),
    };
    summary.innerHTML =
      `<p><strong>Sender:</strong> ${data.sender}</p>` +
      `<p><strong>Sender Surname:</strong> ${data.sender_surname}</p>` +
      `<p><strong>From:</strong> ${data.address_from}</p>` +
      `<p><strong>To:</strong> ${data.address_to}</p>` +
      `<p><strong>Email:</strong> ${data.email}</p>` +
      `<p><strong>Passengers:</strong> ${data.passenger_count}</p>` +
      `<p><strong>Luggage:</strong> ${data.luggage_count}</p>` +
      `<p><strong>Arrival Time:</strong> ${data.arrival_time}</p>` +
      `<p><strong>Car:</strong> ${data.car_choice}</p>`;
  };

  // ===== DATETIME UX (30dk slot + min saat) =====
  (function(){
    function roundToNext30(d){ var ms=1000*60*30; return new Date(Math.ceil(d.getTime()/ms)*ms); }
    function applyDateTimeRules(form){
      var dateEl = getFormField(form, 'input[name="pickup_date"]');
      var timeEl = getFormField(form, 'input[name="pickup_time"]');
      if (!dateEl || !timeEl) return;
      var now = new Date();
      var todayStr = now.getFullYear()+'-'+pad2(now.getMonth()+1)+'-'+pad2(now.getDate());
      dateEl.min = todayStr;
      if (!dateEl.value) dateEl.value = todayStr;
      if (dateEl.value === todayStr){
        var r = roundToNext30(now);
        var minTime = pad2(r.getHours()) + ':' + pad2(r.getMinutes());
        timeEl.min = minTime;
        if (!timeEl.value || timeEl.value < minTime) timeEl.value = minTime;
      } else {
        timeEl.min = '';
      }
      if (timeEl.value){
        var parts = timeEl.value.split(':');
        var hh = +parts[0] || 0, mm = +parts[1] || 0;
        var d = new Date();
        d.setHours(hh, mm, 0, 0);
        d = roundToNext30(d);
        timeEl.value = pad2(d.getHours()) + ':' + pad2(d.getMinutes());
      }
      setDefaultReturnDateTime(form);
    }
    document.addEventListener('DOMContentLoaded', function(){
      var forms = document.querySelectorAll('form.vts-form, form.execvitr-transfer-form, form[data-execvitr-form="1"]');
      Array.prototype.forEach.call(forms, function(form){
        applyDateTimeRules(form);
        var dateEl = getFormField(form, 'input[name="pickup_date"]');
        var timeEl = getFormField(form, 'input[name="pickup_time"]');
        if (dateEl) dateEl.addEventListener('change', function(){ applyDateTimeRules(form); });
        if (timeEl) timeEl.addEventListener('change', function(){ applyDateTimeRules(form); setDefaultReturnDateTime(form); });
      });
    });
  })();

  // ===== Native picker trigger =====
  document.addEventListener('DOMContentLoaded', function(){
    // Return booking toggle
    (function(){
      var forms = document.querySelectorAll('form.vts-form, form.execvitr-transfer-form, form[data-execvitr-form="1"]');
      Array.prototype.forEach.call(forms, function(form){
        var cb = form.querySelector('[name="is_return"]');
        function sync(){
          syncReturnFields(form);
        }
        if (cb) cb.addEventListener('change', sync);
        sync();
      });
    })();

    document.querySelectorAll('input[type="date"], input[type="time"]').forEach(function(input){
      input.addEventListener('click', function(){ if (input.showPicker) input.showPicker(); });
    });
  });

  // ===== Stepper / a11y =====
  (function(){
    var stepsEl = document.getElementById('vts-steps');
    if(!stepsEl) return;
    var c1 = stepsEl.querySelector('.circle[data-step="1"]');
    var c2 = stepsEl.querySelector('.circle[data-step="2"]');
    stepsEl.setAttribute('role','progressbar');
    stepsEl.setAttribute('aria-valuemin','1');
    stepsEl.setAttribute('aria-valuemax','2');
    stepsEl.setAttribute('aria-valuenow','1');
    stepsEl.setAttribute('aria-label','Booking steps');
    function setStep(step){
      if(step === 2){
        c1.classList.add('is-active'); c2.classList.add('is-active');
        stepsEl.style.setProperty('--progress','100%');
        stepsEl.setAttribute('aria-valuenow','2');
      } else {
        c1.classList.add('is-active'); c2.classList.remove('is-active');
        stepsEl.style.setProperty('--progress','0%');
        stepsEl.setAttribute('aria-valuenow','1');
      }
    }
    setStep(1);
    var step2Sel = [
      '.address-section-2 input','.address-section-2 textarea',
      '.cars-options input','.cars-options label',
      '.city-column1 input','.city-column1 .payment-type input'
    ].join(',');
    document.addEventListener('focusin', function(e){ if(e.target && e.target.matches(step2Sel)) setStep(2); });
    document.addEventListener('click',   function(e){ if(e.target && e.target.matches(step2Sel)) setStep(2); });
    var step1Sel = ['.address-section input','.address-section textarea'].join(',');
    document.addEventListener('focusin', function(e){ if(e.target && e.target.matches(step1Sel)) setStep(1); });
  })();

  // ===== AJAX SUBMIT → CHECKOUT =====
  (function($){
    var $forms = $('form.vts-form, form.execvitr-transfer-form, form[data-execvitr-form="1"]');
    if (!$forms.length) $forms = $('#vts-form');
    if (!$forms.length) return;
    var ajaxURL  = (window.execvitr_ajax && execvitr_ajax.ajax_url) || '';
    var ajaxNonce= (window.execvitr_ajax && execvitr_ajax.nonce)   || '';

    function postAction($form, action){
      var data = $form.serializeArray();
      data.push({ name: 'action', value: action });
      if (ajaxNonce) data.push({ name: '_ajax_nonce', value: ajaxNonce });
      return $.ajax({
        url: ajaxURL,
        method: 'POST',
        data: $.param(data),
        dataType: 'json',
        timeout: 45000
      });
    }

    $forms.off('submit.execvitr').on('submit.execvitr', function(ev){
      var $form = $(this);
      var $btn  = $form.find('button[type=submit]');
      var $resp = $form.find('#cc-response, .cc-response').first();
      var originalButtonText = $btn.text();
      if (!$resp.length) $resp = $('#cc-response').first();
      ev.preventDefault();
      if (!ajaxURL){ $resp.text('Ajax endpoint missing.'); return; }
      if ($btn.prop('disabled')) return;
      $btn.prop('disabled', true).text('Gönderiliyor…');
      $resp.text('');

      // Client-side: if return booking is enabled, require return date/time
      try {
        var cb = $form.find('[name="is_return"]').first();
        if (cb.length && cb.is(':checked')) {
          var rd = $form.find('input[name="return_date"]').val();
          var rt = $form.find('input[name="return_time"]').val();
          if (!rd || !rt) {
            markMissingFields(['return_date','return_time']);
            $resp.text('Please select return date and time.');
            $btn.prop('disabled', false).text(originalButtonText);
            return;
          }
        }
      } catch(e) {}


      
      function markMissingFields(keys){
        try {
          // clear previous
          $form.find('.execvitr-missing').removeClass('execvitr-missing');
          (keys||[]).forEach(function(k){
            var sel = null;
            switch(String(k)){
              case 'sender_name': sel = 'input[name="sender_name"]'; break;
              case 'sender_surname': sel = 'input[name="sender_surname"]'; break;
              case 'address_from': sel = '#address_from'; break;
              case 'address_to': sel = '#address_to'; break;
              case 'pickup_date': sel = 'input[name="pickup_date"]'; break;
              case 'pickup_time': sel = 'input[name="pickup_time"]'; break;
              case 'return_date': sel = 'input[name="return_date"]'; break;
              case 'return_time': sel = 'input[name="return_time"]'; break;
              case 'passenger_count': sel = 'input[name="passenger_count"]'; break;
              case 'luggage_count': sel = 'input[name="luggage_count"]'; break;
              case 'car_choice': sel = 'input[name="car_choice"]'; break;
              case 'pickup_phone': sel = 'input[name="pickup_phone"]'; break;
              case 'user_email': sel = 'input[name="user_email"]'; break;
            }
            if (!sel) return;
            var $el = $form.find(sel);
            if ($el && $el.length) $el.addClass('execvitr-missing');
          });
          // focus first
          if (keys && keys.length) {
            var first = String(keys[0]);
            var $first = $form.find(
              first==='address_from' ? '#address_from' :
              first==='address_to' ? '#address_to' :
              first==='car_choice' ? 'input[name="car_choice"]' :
              'input[name="'+first+'"]'
            );
            if ($first && $first.length) {
              $('html, body').animate({ scrollTop: ($first.offset().top - 120) }, 250);
              $first.first().focus();
            }
          }
        } catch(e) {}
      }

function normalizeErr(payload){
        try {
          if (payload && payload.code === "execvitr_required_fields_missing" && payload.missing) {
            markMissingFields(payload.missing);
            return "Please fill in the required fields: " + payload.missing.join(", ");
          }
        } catch(e) {}
        // WP Ajax errors sometimes return objects/arrays; avoid "[object Object]" in UI.
        if (!payload) return 'Bir hata oluştu, lütfen tekrar deneyin.';

        // If already a string
        if (typeof payload === 'string') return payload;

        // If { message: "..." }
        if (typeof payload === 'object') {
          if (payload.message && typeof payload.message === 'string') return payload.message;
          if (payload.data && typeof payload.data === 'string') return payload.data;
          if (payload.error && typeof payload.error === 'string') return payload.error;
          try { return JSON.stringify(payload); } catch(e) {}
        }
        return String(payload);
      }

      var request;
      try {
        request = postAction($form, 'execvitr_form_submit');
      } catch (error) {
        $resp.text('The booking request could not be started. Please try again.');
        $btn.prop('disabled', false).text(originalButtonText);
        return;
      }

      request
        .done(function(res){
          if (res && res.success && res.data && res.data.redirect_url) {
            window.location.assign(res.data.redirect_url);
          } else {
            var raw = (res && (res.data || res.message)) || null;
            $resp.text(normalizeErr(raw));
          }
        })
        .fail(function(xhr){
          var msg = 'Sunucu hatası, lütfen tekrar deneyin.';
          if (xhr && xhr.responseJSON) {
            msg = normalizeErr(xhr.responseJSON.data || xhr.responseJSON.message || xhr.responseJSON);
          }
          $resp.text(msg);
        })
        .always(function(){ $btn.prop('disabled', false).text(originalButtonText); });
    });
  })(window.jQuery || window.$ || function(){ return { length:0 }; });

  // ===== Araç kartı highlight + marka notu =====
  (function(){
    function sync(){
      document.querySelectorAll('.vts-car-card').forEach(function(card){
        var input = card.querySelector('input[type="radio"]');
        card.classList.toggle('selected', !!(input && input.checked));
      });
      var chosen = document.querySelector('input[name="car_choice"]:checked');
      var note = document.querySelector('.brand-note') || document.getElementById('vts-brand-note');
      if (note) note.textContent = (chosen && chosen.dataset.brand) ? (' • ' + chosen.dataset.brand) : '';
    }
    document.addEventListener('change', function(e){ if (e.target && e.target.name === 'car_choice') sync(); });
    document.addEventListener('DOMContentLoaded', sync);
  })();
})();

// wrap price updater to dispatch a hook
(function(){
  try {
    var orig = window.tryUpdatePrice;
    if (typeof orig === 'function') {
      window.tryUpdatePrice = function(){
        var ret;
        try { ret = orig.apply(this, arguments); }
        finally {
          try {
            document.dispatchEvent(new CustomEvent('execvitr:price-updated', {
              detail: {
                from: (document.getElementById('address_from')||{}).value || '',
                to:   (document.getElementById('address_to')||{}).value || ''
              }
            }));
          } catch(e){}
        }
        return ret;
      };
    }
  } catch(e){}
})();
