(function (global) {
  'use strict';

  var CONSENT_PREFIX = 'registropro_supervisor_route_consent_v1_';
  var ENABLE_PREFIX = 'registropro_supervisor_route_enabled_v1_';
  var ALLOWED_ROLES_KEY = 'registropro_supervisor_route_allowed_roles_v1';
  var QUEUE_KEY = 'registropro_supervisor_route_queue_v1';
  var LAST_ERROR_KEY = 'registropro_supervisor_route_last_error_v1';
  var SESSION_KEY_PREFIX = 'registropro_supervisor_route_session_id_v1_';
  var WATCH_INTERVAL_MS = 30000;
  var FLUSH_INTERVAL_MS = 20000;
  var MAX_QUEUE_ITEMS = 300;
  var MIN_DISTANCE_METERS = 20;
  var MAX_ACCURACY_METERS = 250;

  var watchId = null;
  var flushTimer = null;
  var isAskingConsent = false;
  var isFlushing = false;
  var lastAcceptedPoint = null;
  var batteryCache = { level: null, charging: null };

  function safeGetItem(key) {
    try {
      return global.localStorage ? global.localStorage.getItem(key) : null;
    } catch (e) {
      return null;
    }
  }

  function safeSetItem(key, value) {
    try {
      if (global.localStorage) global.localStorage.setItem(key, value);
    } catch (e) {}
  }

  function safeRemoveItem(key) {
    try {
      if (global.localStorage) global.localStorage.removeItem(key);
    } catch (e) {}
  }

  function sessionStorageKey(employeeId) {
    return SESSION_KEY_PREFIX + String(employeeId || 'anonymous');
  }

  function newUuid() {
    try {
      if (global.crypto && typeof global.crypto.randomUUID === 'function') {
        return global.crypto.randomUUID();
      }
    } catch (e) {}
    return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function (c) {
      var r = (Math.random() * 16) | 0;
      var v = c === 'x' ? r : (r & 0x3) | 0x8;
      return v.toString(16);
    });
  }

  function getCurrentSessionId(employeeId) {
    return safeGetItem(sessionStorageKey(employeeId)) || '';
  }

  function setCurrentSessionId(employeeId, id) {
    if (!id) {
      safeRemoveItem(sessionStorageKey(employeeId));
      return;
    }
    safeSetItem(sessionStorageKey(employeeId), id);
  }

  function startNewSession(employeeId) {
    setCurrentSessionId(employeeId, newUuid());
  }

  function clearSession(employeeId) {
    safeRemoveItem(sessionStorageKey(employeeId));
  }

  function attachSessionToPoint(point) {
    var auth = getAuth();
    if (!auth.employeeId) return;
    var sid = getCurrentSessionId(auth.employeeId);
    if (sid) point.route_session_id = sid;
  }

  function notify(msg, type) {
    try {
      if (typeof global.showPanelToast === 'function') {
        global.showPanelToast(msg, type || 'info');
      }
    } catch (e) {}
  }

  function getAuth() {
    return {
      authToken: safeGetItem('auth_token') || '',
      tenantSlug: safeGetItem('tenant_slug') || '',
      employeeId: safeGetItem('employee_id') || '',
      role: safeGetItem('role') || '',
      jobTitle: safeGetItem('job_title') || '',
      departmentName: safeGetItem('department_name') || ''
    };
  }

  function normalizeText(raw) {
    return String(raw || '')
      .toLowerCase()
      .normalize('NFD')
      .replace(/[\u0300-\u036f]/g, '')
      .trim();
  }

  function getAllowedRoleKeywords() {
    var fallback = ['supervisor', 'desenvolvedor', 'coordenador'];
    var source = '';
    try {
      if (typeof global.REGISTRO_PRO_SUPERVISOR_ROUTE_ALLOWED_ROLES === 'string') {
        source = global.REGISTRO_PRO_SUPERVISOR_ROUTE_ALLOWED_ROLES;
      } else {
        source = safeGetItem(ALLOWED_ROLES_KEY) || '';
      }
    } catch (e) {}
    if (!source) return fallback;
    var parsed = String(source)
      .split(',')
      .map(function (s) { return normalizeText(s); })
      .filter(function (s) { return !!s; });
    return parsed.length ? parsed : fallback;
  }

  function isSupervisorRole(roleRaw, jobTitleRaw, departmentRaw) {
    var role = normalizeText(roleRaw);
    var jobTitle = normalizeText(jobTitleRaw);
    var department = normalizeText(departmentRaw);
    var allowed = getAllowedRoleKeywords();
    for (var i = 0; i < allowed.length; i++) {
      var key = allowed[i];
      if (!key) continue;
      if (role.indexOf(key) >= 0 || jobTitle.indexOf(key) >= 0 || department.indexOf(key) >= 0) {
        return true;
      }
    }
    return false;
  }

  function isNativeApp() {
    try {
      if (typeof global.registroProIsNativeApp === 'function') {
        return !!global.registroProIsNativeApp();
      }
      return global.location && global.location.protocol === 'file:';
    } catch (e) {
      return false;
    }
  }

  function consentKey(employeeId) {
    return CONSENT_PREFIX + String(employeeId || 'anonymous');
  }

  function hasConsent(employeeId) {
    return safeGetItem(consentKey(employeeId)) === '1';
  }

  function enableKey(employeeId) {
    return ENABLE_PREFIX + String(employeeId || 'anonymous');
  }

  function isEnabledByUser(employeeId) {
    var v = safeGetItem(enableKey(employeeId));
    if (v === null || v === '') return true;
    return v === '1';
  }

  function saveEnabledByUser(employeeId, enabled) {
    safeSetItem(enableKey(employeeId), enabled ? '1' : '0');
  }

  function saveConsent(employeeId, accepted) {
    if (accepted) {
      safeSetItem(consentKey(employeeId), '1');
      return;
    }
    safeRemoveItem(consentKey(employeeId));
  }

  function readQueue() {
    var raw = safeGetItem(QUEUE_KEY);
    if (!raw) return [];
    try {
      var parsed = JSON.parse(raw);
      return Array.isArray(parsed) ? parsed : [];
    } catch (e) {
      return [];
    }
  }

  function writeQueue(items) {
    safeSetItem(QUEUE_KEY, JSON.stringify(items || []));
  }

  function haversineMeters(lat1, lng1, lat2, lng2) {
    var R = 6371000;
    var dLat = ((lat2 - lat1) * Math.PI) / 180;
    var dLng = ((lng2 - lng1) * Math.PI) / 180;
    var a =
      Math.sin(dLat / 2) * Math.sin(dLat / 2) +
      Math.cos((lat1 * Math.PI) / 180) * Math.cos((lat2 * Math.PI) / 180) *
      Math.sin(dLng / 2) * Math.sin(dLng / 2);
    return 2 * R * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));
  }

  function shouldAcceptPoint(point) {
    if (!lastAcceptedPoint) return true;
    var meters = haversineMeters(
      Number(lastAcceptedPoint.lat),
      Number(lastAcceptedPoint.lng),
      Number(point.lat),
      Number(point.lng)
    );
    return meters >= MIN_DISTANCE_METERS;
  }

  function trimQueue(queue) {
    if (queue.length <= MAX_QUEUE_ITEMS) return queue;
    return queue.slice(queue.length - MAX_QUEUE_ITEMS);
  }

  function attachBatterySnapshot(point) {
    point.battery_level = batteryCache.level;
    point.battery_charging = batteryCache.charging;
  }

  function updateBatteryCache() {
    if (!navigator.getBattery || typeof navigator.getBattery !== 'function') return;
    navigator.getBattery()
      .then(function (battery) {
        function saveNow() {
          batteryCache.level = typeof battery.level === 'number' ? Number((battery.level * 100).toFixed(0)) : null;
          batteryCache.charging = typeof battery.charging === 'boolean' ? battery.charging : null;
        }
        saveNow();
        battery.addEventListener('levelchange', saveNow);
        battery.addEventListener('chargingchange', saveNow);
      })
      .catch(function () {});
  }

  function queuePoint(point) {
    attachSessionToPoint(point);
    var q = readQueue();
    q.push(point);
    q = trimQueue(q);
    writeQueue(q);
  }

  function makePoint(position) {
    var c = position && position.coords ? position.coords : null;
    if (!c) return null;

    var lat = Number(c.latitude);
    var lng = Number(c.longitude);
    var accuracy = Number(c.accuracy);
    if (!isFinite(lat) || !isFinite(lng)) return null;
    if (!isFinite(accuracy) || accuracy <= 0 || accuracy > MAX_ACCURACY_METERS) return null;

    var speed = isFinite(Number(c.speed)) ? Number(c.speed) : null;
    var heading = isFinite(Number(c.heading)) ? Number(c.heading) : null;
    var point = {
      lat: Number(lat.toFixed(7)),
      lng: Number(lng.toFixed(7)),
      accuracy_m: Number(accuracy.toFixed(1)),
      speed_mps: speed !== null ? Number(speed.toFixed(2)) : null,
      heading_deg: heading !== null ? Number(heading.toFixed(1)) : null,
      captured_at: new Date().toISOString(),
      is_mock: !!(c.mocked || c.isFromMockProvider)
    };
    attachBatterySnapshot(point);
    return point;
  }

  function onPosition(position) {
    var point = makePoint(position);
    if (!point) return;
    if (!shouldAcceptPoint(point)) return;
    queuePoint(point);
    lastAcceptedPoint = point;
    flushNow();
  }

  function onPositionError(err) {
    var msg = err && err.message ? String(err.message) : 'Erro ao ler GPS.';
    safeSetItem(LAST_ERROR_KEY, msg);
  }

  function stopWatch() {
    if (watchId !== null && navigator.geolocation && typeof navigator.geolocation.clearWatch === 'function') {
      try {
        navigator.geolocation.clearWatch(watchId);
      } catch (e) {}
    }
    watchId = null;
  }

  function startWatch() {
    if (!navigator.geolocation || typeof navigator.geolocation.watchPosition !== 'function') {
      notify('Este dispositivo nao suporta geolocalizacao continua.', 'warn');
      return;
    }
    stopWatch();
    watchId = navigator.geolocation.watchPosition(onPosition, onPositionError, {
      enableHighAccuracy: true,
      maximumAge: 10000,
      timeout: WATCH_INTERVAL_MS
    });
  }

  function ensureFlushTimer() {
    if (flushTimer) return;
    flushTimer = setInterval(flushNow, FLUSH_INTERVAL_MS);
  }

  function stopFlushTimer() {
    if (!flushTimer) return;
    clearInterval(flushTimer);
    flushTimer = null;
  }

  function flushNow() {
    if (isFlushing) return;
    var auth = getAuth();
    var q = readQueue();
    if (!auth.authToken || q.length === 0) return;
    if (typeof global.registroProGetSupervisorRouteTrackApiUrl !== 'function') return;

    var url = global.registroProGetSupervisorRouteTrackApiUrl();
    var batch = q.slice(0, 50);
    isFlushing = true;
    var batchSession = batch[0] && batch[0].route_session_id ? String(batch[0].route_session_id) : '';

    fetch(url, {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json',
        'Accept': 'application/json',
        'Authorization': 'Bearer ' + auth.authToken
      },
      body: JSON.stringify({
        points: batch,
        app_version: 'cordova-webview',
        client_batch_id: 'batch_' + Date.now(),
        route_session_id: batchSession || undefined
      })
    })
      .then(function (res) {
        return res.json().catch(function () { return null; });
      })
      .then(function (json) {
        if (!json || json.ok !== true) return;
        var current = readQueue();
        current.splice(0, batch.length);
        writeQueue(current);
      })
      .catch(function () {})
      .finally(function () {
        isFlushing = false;
      });
  }

  function requestConsentIfNeeded(employeeId) {
    if (!employeeId || hasConsent(employeeId) || isAskingConsent) return Promise.resolve(true);
    isAskingConsent = true;
    return new Promise(function (resolve) {
      var accepted = global.confirm(
        'Permite rastreamento de rota em tempo real durante o expediente para fins de supervisao e seguranca?\n\n' +
        'Sua localizacao sera enviada ao RH para acompanhamento de campo.'
      );
      saveConsent(employeeId, accepted);
      if (!accepted) {
        notify('Rastreamento de rota nao ativado sem consentimento.', 'warn');
      }
      isAskingConsent = false;
      resolve(accepted);
    });
  }

  function start() {
    var auth = getAuth();
    if (!isNativeApp()) return;
    if (!auth.authToken || !auth.employeeId) return;
    if (!isSupervisorRole(auth.role, auth.jobTitle, auth.departmentName)) return;
    if (!isEnabledByUser(auth.employeeId)) {
      stopWatch();
      stopFlushTimer();
      return;
    }

    requestConsentIfNeeded(auth.employeeId).then(function (allowed) {
      if (!allowed) {
        stopWatch();
        stopFlushTimer();
        return;
      }
      if (!getCurrentSessionId(auth.employeeId)) {
        startNewSession(auth.employeeId);
      }
      updateBatteryCache();
      startWatch();
      ensureFlushTimer();
      flushNow();
    });
  }

  function stop() {
    stopWatch();
    stopFlushTimer();
  }

  function clearQueue() {
    writeQueue([]);
  }

  function isEnabled() {
    var auth = getAuth();
    if (!auth.employeeId) return true;
    return isEnabledByUser(auth.employeeId);
  }

  function setEnabled(enabled) {
    var auth = getAuth();
    if (!auth.employeeId) return false;
    saveEnabledByUser(auth.employeeId, !!enabled);
    if (enabled) {
      startNewSession(auth.employeeId);
      lastAcceptedPoint = null;
      start();
    } else {
      flushNow();
      stop();
      clearSession(auth.employeeId);
      lastAcceptedPoint = null;
    }
    return true;
  }

  function isSupervisorCurrentUser() {
    var auth = getAuth();
    return isSupervisorRole(auth.role, auth.jobTitle, auth.departmentName);
  }

  global.registroProSupervisorRouteTracker = {
    start: start,
    stop: stop,
    flushNow: flushNow,
    clearQueue: clearQueue,
    isEnabled: isEnabled,
    setEnabled: setEnabled,
    isSupervisorCurrentUser: isSupervisorCurrentUser
  };
})(typeof window !== 'undefined' ? window : this);
