/**
 * Geolocalización y selects anidados LATAM — instalador Flexia.
 */
(function (global) {
  'use strict';

  var geoCache = null;
  var geoLoadPromise = null;
  var NOMINATIM_UA = 'Flexia-Installer/1.0 (contacto@flexia.local)';

  function el(tag, attrs, children) {
    var node = document.createElement(tag);
    if (attrs) {
      Object.keys(attrs).forEach(function (k) {
        if (k === 'className') node.className = attrs[k];
        else if (k === 'text') node.textContent = attrs[k];
        else node.setAttribute(k, attrs[k]);
      });
    }
    if (children) {
      children.forEach(function (c) {
        if (c) node.appendChild(typeof c === 'string' ? document.createTextNode(c) : c);
      });
    }
    return node;
  }

  function loadGeoData(dataUrl) {
    if (geoCache) return Promise.resolve(geoCache);
    if (geoLoadPromise) return geoLoadPromise;
    geoLoadPromise = fetch(dataUrl, { credentials: 'same-origin' })
      .then(function (r) {
        if (!r.ok) throw new Error('geo data');
        return r.json();
      })
      .then(function (j) {
        geoCache = j;
        return j;
      })
      .catch(function () {
        geoCache = { version: 1, regions: [], otherCountries: [] };
        return geoCache;
      });
    return geoLoadPromise;
  }

  function composeAddress(parts) {
    var out = [];
    ['street', 'city', 'state', 'country'].forEach(function (k) {
      var v = (parts[k] || '').trim();
      if (v) out.push(v);
    });
    return out.join(', ');
  }

  function pickCityFromNominatim(addr) {
    if (!addr) return '';
    return (
      addr.city ||
      addr.town ||
      addr.village ||
      addr.municipality ||
      addr.county ||
      addr.suburb ||
      ''
    );
  }

  function pickStateFromNominatim(addr) {
    if (!addr) return '';
    return addr.state || addr.region || addr.state_district || '';
  }

  function reverseGeocode(lat, lon) {
    var url =
      'https://nominatim.openstreetmap.org/reverse?format=jsonv2&addressdetails=1&lat=' +
      encodeURIComponent(lat) +
      '&lon=' +
      encodeURIComponent(lon);
    return fetch(url, {
      method: 'GET',
      headers: { Accept: 'application/json', 'User-Agent': NOMINATIM_UA },
    })
      .then(function (r) {
        return r.json();
      })
      .catch(function () {
        return null;
      });
  }

  function findCountry(data, code) {
    if (!code) return null;
    var u = String(code).toUpperCase();
    var i;
    for (i = 0; i < (data.regions || []).length; i++) {
      if (data.regions[i].code === u) return data.regions[i];
    }
    for (i = 0; i < (data.otherCountries || []).length; i++) {
      if (data.otherCountries[i].code === u) return data.otherCountries[i];
    }
    return null;
  }

  function findState(country, stateName, stateCode) {
    if (!country || !country.states) return null;
    var sn = (stateName || '').toLowerCase();
    var sc = (stateCode || '').toUpperCase();
    for (var i = 0; i < country.states.length; i++) {
      var s = country.states[i];
      if (sc && s.code && s.code.toUpperCase() === sc) return s;
      if (sn && s.name && s.name.toLowerCase() === sn) return s;
    }
    for (var j = 0; j < country.states.length; j++) {
      var st = country.states[j];
      if (sn && st.name && st.name.toLowerCase().indexOf(sn) >= 0) return st;
      if (sn && sn.indexOf(st.name.toLowerCase()) >= 0) return st;
    }
    return null;
  }

  function findCity(state, cityName) {
    if (!state || !state.cities || !cityName) return '';
    var cn = cityName.toLowerCase();
    for (var i = 0; i < state.cities.length; i++) {
      if (state.cities[i].toLowerCase() === cn) return state.cities[i];
    }
    for (var j = 0; j < state.cities.length; j++) {
      if (state.cities[j].toLowerCase().indexOf(cn) >= 0 || cn.indexOf(state.cities[j].toLowerCase()) >= 0) {
        return state.cities[j];
      }
    }
    return cityName;
  }

  function fillSelect(sel, options, placeholder, selectedValue) {
    if (!sel) return;
    sel.innerHTML = '';
    sel.appendChild(el('option', { value: '', text: placeholder }));
    options.forEach(function (opt) {
      var val = typeof opt === 'string' ? opt : opt.value;
      var label = typeof opt === 'string' ? opt : opt.label;
      var o = el('option', { value: val, text: label });
      if (selectedValue && String(selectedValue) === String(val)) o.selected = true;
      sel.appendChild(o);
    });
  }

  function isPhysicalMobileDevice() {
    if (!global.navigator) return false;
    var ua = global.navigator.userAgent || '';
    if (/Android|iPhone|iPad|iPod|Mobile|webOS|BlackBerry|IEMobile|Opera Mini/i.test(ua)) {
      return true;
    }
    if (global.matchMedia) {
      if (global.matchMedia('(pointer: coarse)').matches && global.matchMedia('(max-width: 1024px)').matches) {
        return true;
      }
    }
    return false;
  }

  function dispatchGeoCountry(countryCode, source) {
    var cc = (countryCode || '').toUpperCase();
    if (cc.length !== 2) return;
    try {
      document.dispatchEvent(
        new CustomEvent('install-geo-country', {
          detail: { countryCode: cc, source: source || 'manual' },
        })
      );
    } catch (e) {
      /* IE fallback omitted */
    }
  }

  function updateGeoMap(block, lat, lon) {
    var mapWrap = block.querySelector('[data-geo-map]');
    var frame = block.querySelector('[data-geo-map-frame]');
    if (!mapWrap || !frame) return;
    if (lat == null || lon == null || !isFinite(lat) || !isFinite(lon)) {
      mapWrap.hidden = true;
      frame.removeAttribute('src');
      return;
    }
    var d = 0.01;
    var left = lon - d;
    var right = lon + d;
    var top = lat + d;
    var bottom = lat - d;
    var src =
      'https://www.openstreetmap.org/export/embed.html?bbox=' +
      [left, bottom, right, top].join('%2C') +
      '&layer=mapnik&marker=' +
      encodeURIComponent(lat) +
      '%2C' +
      encodeURIComponent(lon);
    frame.setAttribute('src', src);
    mapWrap.hidden = false;
  }

  function getLocationFromBlock(block) {
    var countrySel = block.querySelector('[data-geo-country]');
    var stateSel = block.querySelector('[data-geo-state]');
    var citySel = block.querySelector('[data-geo-city]');
    var cityText = block.querySelector('[data-geo-city-text]');
    var street = block.querySelector('[data-geo-street]');
    var countryOpt = countrySel && countrySel.options[countrySel.selectedIndex];
    var stateOpt = stateSel && stateSel.options[stateSel.selectedIndex];
    var cityVal = '';
    if (citySel && citySel.offsetParent !== null) {
      cityVal = citySel.value;
    } else if (cityText) {
      cityVal = cityText.value;
    }
    return {
      street: street ? street.value.trim() : '',
      city: cityVal.trim(),
      state: stateOpt && stateOpt.value ? stateOpt.text : (block.querySelector('[data-geo-state-text]') || {}).value || '',
      stateCode: stateSel ? stateSel.value : '',
      country: countryOpt && countryOpt.value ? countryOpt.text : (block.querySelector('[data-geo-country-text]') || {}).value || '',
      countryCode: countrySel ? countrySel.value : '',
      coordinates: block._installCoords || null,
    };
  }

  function syncHidden(block) {
    var loc = getLocationFromBlock(block);
    var addrField = block.querySelector('[data-geo-address]');
    var jsonField = block.querySelector('[data-geo-json]');
    var composed = composeAddress(loc);
    if (addrField) addrField.value = composed;
    if (jsonField) {
      jsonField.value = JSON.stringify({
        street: loc.street,
        city: loc.city,
        state: loc.state,
        stateCode: loc.stateCode,
        country: loc.country,
        countryCode: loc.countryCode,
        coordinates: loc.coordinates,
      });
    }
    if (loc.coordinates && loc.coordinates.lat != null && loc.coordinates.lon != null) {
      updateGeoMap(block, loc.coordinates.lat, loc.coordinates.lon);
    } else {
      updateGeoMap(block, null, null);
    }
  }

  function initLocationBlock(root, options) {
    if (!root || root.getAttribute('data-geo-inited') === '1') return;
    root.setAttribute('data-geo-inited', '1');
    options = options || {};
    var dataUrl = options.dataUrl || '';
    var initial = options.initial || {};
    var readonly = !!options.readonly;

    var countrySel = root.querySelector('[data-geo-country]');
    var stateSel = root.querySelector('[data-geo-state]');
    var citySel = root.querySelector('[data-geo-city]');
    var cityTextWrap = root.querySelector('[data-geo-city-text-wrap]');
    var cityText = root.querySelector('[data-geo-city-text]');
    var stateTextWrap = root.querySelector('[data-geo-state-text-wrap]');
    var stateText = root.querySelector('[data-geo-state-text]');
    var street = root.querySelector('[data-geo-street]');
    var gpsBtn = root.querySelector('[data-geo-gps]');
    var status = root.querySelector('[data-geo-status]');
    var geoBusy = false;

    function setReadonlyMode(on) {
      root.querySelectorAll('select,input,button[data-geo-gps]').forEach(function (n) {
        if (n.hasAttribute('data-geo-keep')) return;
        n.disabled = !!on;
      });
      if (gpsBtn) gpsBtn.style.display = on ? 'none' : '';
    }

    if (readonly) setReadonlyMode(true);

    function populateStates(country, selectedStateCode, selectedStateName, selectedCity) {
      if (!country) {
        fillSelect(stateSel, [], 'Estado / provincia', '');
        fillSelect(citySel, [], 'Ciudad', '');
        if (stateTextWrap) stateTextWrap.style.display = 'none';
        if (cityTextWrap) cityTextWrap.style.display = 'none';
        return;
      }
      var states = country.states || [];
      var useFreeText = states.length === 0 || states.length === 1 && states[0].code && states[0].code.endsWith('-GEN');
      if (useFreeText) {
        if (stateSel) stateSel.style.display = 'none';
        if (citySel) citySel.style.display = 'none';
        if (stateTextWrap) {
          stateTextWrap.style.display = '';
          if (stateText && selectedStateName) stateText.value = selectedStateName;
        }
        if (cityTextWrap) {
          cityTextWrap.style.display = '';
          if (cityText && selectedCity) cityText.value = selectedCity;
        }
        return;
      }
      if (stateSel) stateSel.style.display = '';
      if (citySel) citySel.style.display = '';
      if (stateTextWrap) stateTextWrap.style.display = 'none';
      if (cityTextWrap) cityTextWrap.style.display = 'none';
      var stateOpts = states.map(function (s) {
        return { value: s.code, label: s.name };
      });
      fillSelect(stateSel, stateOpts, 'Estado / provincia', selectedStateCode);
      var st = findState(country, selectedStateName, selectedStateCode);
      if (!st && selectedStateCode) {
        for (var i = 0; i < states.length; i++) {
          if (states[i].code === selectedStateCode) {
            st = states[i];
            break;
          }
        }
      }
      var cities = st && st.cities ? st.cities : [];
      var cityOpts = cities.map(function (c) {
        return { value: c, label: c };
      });
      var cityPick = findCity(st, selectedCity);
      fillSelect(citySel, cityOpts, 'Ciudad', cityPick || selectedCity);
    }

    function onStateChange() {
      var code = countrySel ? countrySel.value : '';
      loadGeoData(dataUrl).then(function (data) {
        var country = findCountry(data, code);
        var stCode = stateSel ? stateSel.value : '';
        var st = country ? findState(country, '', stCode) : null;
        var cities = st && st.cities ? st.cities : [];
        fillSelect(
          citySel,
          cities.map(function (c) {
            return { value: c, label: c };
          }),
          'Ciudad',
          ''
        );
        syncHidden(root);
      });
    }

    function applyNominatimResult(j, fromGps) {
      if (!j || !j.address) return;
      var addr = j.address;
      var cc = (addr.country_code || '').toUpperCase();
      var stateName = pickStateFromNominatim(addr);
      var cityName = pickCityFromNominatim(addr);
      var streetParts = [];
      if (addr.road) streetParts.push(addr.road);
      if (addr.house_number) streetParts.push(addr.house_number);
      if (street) {
        if (fromGps && isPhysicalMobileDevice() && streetParts.length) {
          street.value = streetParts.join(' ');
        } else if (fromGps) {
          street.value = '';
        }
      }

      loadGeoData(dataUrl).then(function (data) {
        fillSelect(
          countrySel,
          (data.regions || [])
            .map(function (c) {
              return { value: c.code, label: c.name };
            })
            .concat(
              (data.otherCountries || []).map(function (c) {
                return { value: c.code, label: c.name };
              })
            ),
          'País',
          cc
        );
        var country = findCountry(data, cc);
        if (country) {
          var st = findState(country, stateName, '');
          populateStates(country, st ? st.code : '', stateName, cityName);
        }
        syncHidden(root);
        if (cc) dispatchGeoCountry(cc, 'gps');
      });
    }

    function onCountryChange() {
      var code = countrySel ? countrySel.value : '';
      loadGeoData(dataUrl).then(function (data) {
        var country = findCountry(data, code);
        populateStates(country, '', '', '');
        syncHidden(root);
        if (code) dispatchGeoCountry(code, 'manual');
      });
    }

    function runGps() {
      if (geoBusy || readonly) return;
      if (!global.navigator || !global.navigator.geolocation) {
        if (status) status.textContent = 'Geolocalización no disponible en este navegador.';
        return;
      }
      geoBusy = true;
      if (status) status.textContent = 'Obteniendo ubicación…';
      global.navigator.geolocation.getCurrentPosition(
        function (pos) {
          var c = {
            lat: pos.coords.latitude,
            lon: pos.coords.longitude,
            accuracy: pos.coords.accuracy,
            timestamp: pos.timestamp || Date.now(),
            source: 'geolocation',
          };
          root._installCoords = c;
          root._installGeoCountryPending = true;
          updateGeoMap(root, c.lat, c.lon);
          reverseGeocode(c.lat, c.lon).then(function (j) {
            applyNominatimResult(j, true);
            if (status) status.textContent = '';
            geoBusy = false;
          });
        },
        function (err) {
          geoBusy = false;
          root._installCoords = null;
          var code = err && typeof err.code === 'number' ? err.code : 0;
          if (status) {
            status.textContent =
              code === 1
                ? 'Permiso de ubicación denegado. Puedes elegir país y ciudad manualmente.'
                : 'No se pudo obtener la ubicación. Elige país y ciudad manualmente.';
          }
        },
        { enableHighAccuracy: true, timeout: 12000, maximumAge: 0 }
      );
    }

    loadGeoData(dataUrl).then(function (data) {
      var regionOpts = (data.regions || []).map(function (c) {
        return { value: c.code, label: c.name };
      });
      var otherOpts = (data.otherCountries || []).map(function (c) {
        return { value: c.code, label: c.name };
      });
      if (countrySel) {
        countrySel.innerHTML = '';
        countrySel.appendChild(el('option', { value: '', text: 'País' }));
        if (regionOpts.length) {
          var og = el('optgroup', { label: 'Latinoamérica y España' });
          regionOpts.forEach(function (o) {
            og.appendChild(el('option', { value: o.value, text: o.label }));
          });
          countrySel.appendChild(og);
        }
        if (otherOpts.length) {
          var og2 = el('optgroup', { label: 'Otros países' });
          otherOpts.forEach(function (o) {
            og2.appendChild(el('option', { value: o.value, text: o.label }));
          });
          countrySel.appendChild(og2);
        }
      }
      var cc = (initial.countryCode || '').toUpperCase();
      if (countrySel && cc) countrySel.value = cc;
      var country = findCountry(data, cc);
      populateStates(country, initial.stateCode || '', initial.state || '', initial.city || '');
      if (street && initial.street) street.value = initial.street;
      if (initial.coordinates) root._installCoords = initial.coordinates;
      syncHidden(root);
    });

    if (countrySel) countrySel.addEventListener('change', onCountryChange);
    if (stateSel) stateSel.addEventListener('change', onStateChange);
    if (citySel) citySel.addEventListener('change', function () {
      syncHidden(root);
    });
    if (street) street.addEventListener('input', function () {
      syncHidden(root);
    });
    if (cityText) cityText.addEventListener('input', function () {
      syncHidden(root);
    });
    if (stateText) stateText.addEventListener('input', function () {
      syncHidden(root);
    });
    if (gpsBtn) gpsBtn.addEventListener('click', runGps);

    root._installGeoSync = function () {
      syncHidden(root);
    };
  }

  global.InstallGeo = {
    loadGeoData: loadGeoData,
    initLocationBlock: initLocationBlock,
    composeAddress: composeAddress,
    reverseGeocode: reverseGeocode,
  };
})(typeof window !== 'undefined' ? window : globalThis);
