(function () {
    'use strict';

    var VERSION = 'p15_bi_mobile_navigation';
    var DEFAULT_MODE = 'value';

    var STATUS_COLORS = {
        activo: '#2F80ED',
        nuevo: '#27AE60',
        en_riesgo: '#F2994A',
        dormido: '#BB6BD9',
        perdido: '#EB5757',
        sin_compra: '#8B949E'
    };

    var PIPELINE_COLORS = {
        high: '#27AE60',
        medium: '#F2994A',
        low: '#56CCF2',
        none: '#8B949E'
    };

    var SEGMENT_COLORS = {
        customer: '#2F80ED',
        pipeline: '#27AE60',
        quoted_only: '#F2994A',
        prospect: '#8B949E'
    };

    var MODE_LABELS = {
        value: 'Valor comercial',
        pipeline: 'Pipeline',
        risk: 'Riesgo',
        coverage: 'Cobertura',
        detail: 'Detalle'
    };

    function getPoints() {
        var script = document.getElementById('customerTerritoryPoints');
        if (!script) return [];
        try {
            var parsed = JSON.parse(script.textContent || '[]');
            return Array.isArray(parsed) ? parsed : [];
        } catch (error) {
            console.error('[customer-territory-map] JSON invalido', error);
            return [];
        }
    }

    function setMessage(container, text) {
        var message = container.querySelector('[data-map-message]');
        if (message) message.textContent = text;
    }

    function setTitle(container, text) {
        var title = container.querySelector('[data-map-title]');
        if (title) title.textContent = text;
    }

    function loadGoogleMaps(key, callback, onError) {
        function ready() {
            if (window.google && window.google.maps && window.google.maps.Map) {
                callback();
                return;
            }
            if (typeof onError === 'function') {
                onError('Google Maps no quedo disponible despues de cargar el script.');
            }
        }

        if (window.google && window.google.maps && window.google.maps.Map) {
            ready();
            return;
        }

        window.__ICY_GOOGLE_MAPS_CALLBACKS = window.__ICY_GOOGLE_MAPS_CALLBACKS || [];
        window.__ICY_GOOGLE_MAPS_CALLBACKS.push(ready);

        if (window.__ICY_GOOGLE_MAPS_LOADING) return;

        window.__ICY_GOOGLE_MAPS_LOADING = true;
        window.__icyCustomerTerritoryMapReady = function () {
            var callbacks = window.__ICY_GOOGLE_MAPS_CALLBACKS || [];
            window.__ICY_GOOGLE_MAPS_LOADING = false;
            window.__ICY_GOOGLE_MAPS_CALLBACKS = [];
            callbacks.forEach(function (fn) {
                if (typeof fn === 'function') fn();
            });
        };

        var script = document.createElement('script');
        script.src = 'https://maps.googleapis.com/maps/api/js?key=' + encodeURIComponent(key) + '&callback=__icyCustomerTerritoryMapReady&v=weekly';
        script.async = true;
        script.defer = true;
        script.onerror = function () {
            window.__ICY_GOOGLE_MAPS_LOADING = false;
            window.__ICY_GOOGLE_MAPS_CALLBACKS = [];
            if (typeof onError === 'function') {
                onError('No se pudo cargar Google Maps. Revisa key, dominio autorizado, facturacion y Maps JavaScript API.');
            }
        };
        document.head.appendChild(script);
    }

    function toNumber(value) {
        var parsed = Number(value || 0);
        return Number.isFinite(parsed) ? parsed : 0;
    }

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

    function escapeHtml(value) {
        return String(value || '')
            .replace(/&/g, '&amp;')
            .replace(/</g, '&lt;')
            .replace(/>/g, '&gt;')
            .replace(/"/g, '&quot;')
            .replace(/'/g, '&#039;');
    }

    function formatCurrency(value) {
        var amount = toNumber(value);
        try {
            return new Intl.NumberFormat('es-CL', {
                style: 'currency',
                currency: 'CLP',
                maximumFractionDigits: 0
            }).format(amount);
        } catch (error) {
            return '$' + Math.round(amount).toString().replace(/\B(?=(\d{3})+(?!\d))/g, '.');
        }
    }

    function formatCompact(value) {
        var amount = toNumber(value);
        if (amount >= 1000000000) return '$' + (amount / 1000000000).toFixed(1).replace('.', ',') + 'B';
        if (amount >= 1000000) return '$' + (amount / 1000000).toFixed(amount >= 10000000 ? 0 : 1).replace('.', ',') + 'M';
        if (amount >= 1000) return '$' + Math.round(amount / 1000) + 'K';
        return '$' + Math.round(amount);
    }

    function pointInitials(point) {
        var name = String(point.name || point.legal_name || '').trim();
        var words = name.split(/\s+/).filter(Boolean);
        if (!words.length) return '';
        if (words.length === 1) return words[0].slice(0, 2).toUpperCase();
        return (words[0].slice(0, 1) + words[1].slice(0, 1)).toUpperCase();
    }

    function isRiskStatus(status) {
        return status === 'en_riesgo' || status === 'dormido' || status === 'perdido';
    }

    function metricValue(point, mode) {
        if (mode === 'pipeline') {
            return toNumber(point.weighted_pipeline_value) || toNumber(point.open_pipeline_value);
        }
        if (mode === 'risk') {
            return isRiskStatus(point.customer_status) ? toNumber(point.total_net_sales) : 0;
        }
        if (mode === 'coverage') {
            return 1;
        }
        return toNumber(point.sales_last_12m) || toNumber(point.total_net_sales);
    }

    function valueRange(points, mode) {
        var values = points.map(function (point) {
            return metricValue(point, mode);
        }).filter(function (value) {
            return value > 0;
        });

        if (!values.length) return { min: 0, max: 0 };
        return {
            min: Math.min.apply(Math, values),
            max: Math.max.apply(Math, values)
        };
    }

    function markerScale(point, mode, range) {
        if (mode === 'coverage') return 7;

        var value = metricValue(point, mode);
        if (value <= 0 || range.max <= 0) return 4.8;

        var minScale = mode === 'pipeline' ? 7 : 6.5;
        var maxScale = mode === 'risk' ? 22 : 24;
        var scaled = range.max === range.min ? 1 : Math.sqrt((value - range.min) / (range.max - range.min));
        return clamp(minScale + scaled * (maxScale - minScale), minScale, maxScale);
    }

    function pipelineCategory(point) {
        var weighted = toNumber(point.weighted_pipeline_value);
        var hot = toNumber(point.hot_opportunities);
        var open = toNumber(point.open_opportunities);
        if (weighted <= 0 && open <= 0) return 'none';
        if (hot > 0 || weighted >= 1000000) return 'high';
        if (weighted >= 250000 || open >= 2) return 'medium';
        return 'low';
    }

    function markerColor(point, mode) {
        if (mode === 'pipeline') return PIPELINE_COLORS[pipelineCategory(point)] || PIPELINE_COLORS.none;
        if (mode === 'coverage') return SEGMENT_COLORS[point.segment_key] || SEGMENT_COLORS.prospect;
        return STATUS_COLORS[point.customer_status] || STATUS_COLORS.sin_compra;
    }

    function markerOpacity(point, mode) {
        if (mode === 'risk' && !isRiskStatus(point.customer_status)) return 0.25;
        if (mode === 'pipeline' && metricValue(point, mode) <= 0) return 0.28;
        if (mode === 'value' && metricValue(point, mode) <= 0) return 0.32;
        return mode === 'coverage' ? 0.72 : 0.78;
    }

    function markerZIndex(point, mode) {
        return Math.round(1000 + markerScale(point, mode, valueRange([point], mode)) * 10 + metricValue(point, mode) / 100000);
    }

    function locationText(point) {
        return [point.district, point.city, point.region, point.country].filter(Boolean).join(', ');
    }

    function statusLabel(point) {
        return point.customer_status_label || point.customer_status || 'Sin estado';
    }

    function modeDescription(mode) {
        if (mode === 'pipeline') return 'tamano = pipeline ponderado; color = intensidad de oportunidad.';
        if (mode === 'risk') return 'tamano = ventas historicas en riesgo; color = estado de cliente.';
        if (mode === 'coverage') return 'tamano fijo; color = tipo de relacion comercial.';
        if (mode === 'detail') return 'marcadores individuales para abrir ficha de cliente.';
        return 'tamano = ventas 12 meses; color = estado de cliente.';
    }

    function infoHtml(point) {
        var sales12m = toNumber(point.sales_last_12m);
        var totalSales = toNumber(point.total_net_sales);
        var weightedPipeline = toNumber(point.weighted_pipeline_value);
        var openPipeline = toNumber(point.open_pipeline_value);
        var days = point.days_since_last_purchase === null || point.days_since_last_purchase === undefined ? 'N/D' : String(point.days_since_last_purchase);

        return '<div class="territory-info-window">'
            + '<strong>' + escapeHtml(point.name || 'Cliente') + '</strong>'
            + (point.legal_name ? '<small>' + escapeHtml(point.legal_name) + '</small>' : '')
            + (locationText(point) ? '<span>' + escapeHtml(locationText(point)) + '</span>' : '')
            + '<small>Estado: ' + escapeHtml(statusLabel(point)) + ' · Ultima compra: ' + escapeHtml(point.last_purchase_date || 'N/D') + ' (' + escapeHtml(days) + ' dias)</small>'
            + '<small>Ventas 12M: ' + escapeHtml(formatCurrency(sales12m)) + ' · Historico: ' + escapeHtml(formatCurrency(totalSales)) + '</small>'
            + '<small>Pipeline pond.: ' + escapeHtml(formatCurrency(weightedPipeline)) + ' · Pipeline bruto: ' + escapeHtml(formatCurrency(openPipeline)) + '</small>'
            + '<small>Ops. abiertas: ' + escapeHtml(point.open_opportunities || 0) + ' · Cotizaciones: ' + escapeHtml(point.quote_count || 0) + '</small>'
            + (point.next_action_due ? '<small>Proxima accion: ' + escapeHtml(point.next_action_due) + '</small>' : '')
            + (point.quote_statuses ? '<small>Estados cot.: ' + escapeHtml(point.quote_statuses) + '</small>' : '')
            + '<a href="' + encodeURI(point.url || '#') + '">Abrir ficha comercial</a>'
            + '</div>';
    }

    function createMarker(point, map, infoWindow, mode, range) {
        var lat = toNumber(point.lat);
        var lng = toNumber(point.lng);
        if (!Number.isFinite(lat) || !Number.isFinite(lng) || (lat === 0 && lng === 0)) return null;

        var position = { lat: lat, lng: lng };
        var markerOptions = {
            position: position,
            map: map,
            title: point.name || 'Cliente',
            zIndex: markerZIndex(point, mode)
        };

        if (mode !== 'detail') {
            var scale = markerScale(point, mode, range);
            var color = markerColor(point, mode);
            markerOptions.icon = {
                path: google.maps.SymbolPath.CIRCLE,
                scale: scale,
                fillColor: color,
                fillOpacity: markerOpacity(point, mode),
                strokeColor: '#FFFFFF',
                strokeOpacity: 0.88,
                strokeWeight: scale >= 10 ? 1.8 : 1.2
            };
            if (scale >= 12) {
                markerOptions.label = {
                    text: pointInitials(point),
                    color: '#FFFFFF',
                    fontSize: scale >= 18 ? '11px' : '9px',
                    fontWeight: '700'
                };
            }
        }

        var marker = new google.maps.Marker(markerOptions);
        marker.addListener('click', function () {
            infoWindow.setContent(infoHtml(point));
            infoWindow.open(map, marker);
        });
        return marker;
    }

    function clearMarkers(markers) {
        markers.forEach(function (marker) {
            marker.setMap(null);
        });
        markers.length = 0;
    }

    function setButtonState(container, activeMode) {
        container.querySelectorAll('[data-territory-map-mode]').forEach(function (button) {
            var mode = button.getAttribute('data-territory-map-mode');
            var isActive = mode === activeMode;
            button.classList.toggle('btn-primary', isActive);
            button.classList.toggle('btn-outline', !isActive);
            button.setAttribute('aria-pressed', isActive ? 'true' : 'false');
        });
    }

    function sortedLeaders(points, mode) {
        return points.slice().filter(function (point) {
            return metricValue(point, mode) > 0;
        }).sort(function (a, b) {
            return metricValue(b, mode) - metricValue(a, mode);
        }).slice(0, 5);
    }

    function colorLegend(mode) {
        if (mode === 'pipeline') {
            return [
                ['Alta', PIPELINE_COLORS.high],
                ['Media', PIPELINE_COLORS.medium],
                ['Baja', PIPELINE_COLORS.low],
                ['Sin pipeline', PIPELINE_COLORS.none]
            ];
        }
        if (mode === 'coverage') {
            return [
                ['Cliente', SEGMENT_COLORS.customer],
                ['Pipeline', SEGMENT_COLORS.pipeline],
                ['Solo cotizo', SEGMENT_COLORS.quoted_only],
                ['Prospecto', SEGMENT_COLORS.prospect]
            ];
        }
        return [
            ['Activo', STATUS_COLORS.activo],
            ['Nuevo', STATUS_COLORS.nuevo],
            ['En riesgo', STATUS_COLORS.en_riesgo],
            ['Dormido', STATUS_COLORS.dormido],
            ['Perdido', STATUS_COLORS.perdido]
        ];
    }

    function renderLegend(container, mapEl, points, mode, range) {
        var legend = mapEl.querySelector('[data-map-legend]');
        if (!legend) {
            legend = document.createElement('div');
            legend.className = 'territory-map-legend territory-map-legend-collapsible';
            legend.setAttribute('data-map-legend', 'true');
            legend.setAttribute('data-expanded', 'false');
            mapEl.appendChild(legend);
        }

        var isExpanded = legend.getAttribute('data-expanded') === 'true';
        var leaders = sortedLeaders(points, mode);
        var leadersHtml = leaders.map(function (point) {
            var value = mode === 'coverage' ? statusLabel(point) : formatCompact(metricValue(point, mode));
            return '<span class="territory-map-legend-client"><i class="territory-map-legend-swatch" style="background:' + markerColor(point, mode) + '"></i><span>'
                + escapeHtml(point.name || 'Cliente') + '</span><strong>' + escapeHtml(value) + '</strong></span>';
        }).join('');

        var colorsHtml = colorLegend(mode).map(function (item) {
            return '<span class="territory-map-color-key"><i style="background:' + item[1] + '"></i>' + escapeHtml(item[0]) + '</span>';
        }).join('');

        var minText = mode === 'coverage' || mode === 'detail' ? '' : formatCompact(range.min);
        var maxText = mode === 'coverage' || mode === 'detail' ? '' : formatCompact(range.max);
        var metricLabel = mode === 'coverage' || mode === 'detail'
            ? String(points.length) + ' puntos'
            : escapeHtml(minText) + ' - ' + escapeHtml(maxText);
        var toggleLabel = isExpanded ? 'Ocultar leyenda' : 'Ver leyenda';

        legend.setAttribute('data-expanded', isExpanded ? 'true' : 'false');
        legend.innerHTML = '<button class="territory-map-legend-toggle" type="button" aria-expanded="' + (isExpanded ? 'true' : 'false') + '">'
            + '<span class="territory-map-legend-toggle-main"><strong>' + escapeHtml(MODE_LABELS[mode] || MODE_LABELS.value) + '</strong><small>' + escapeHtml(toggleLabel) + '</small></span>'
            + '<span class="territory-map-legend-toggle-value">' + metricLabel + '</span>'
            + '<i class="territory-map-legend-toggle-icon" aria-hidden="true">' + (isExpanded ? '−' : '+') + '</i>'
            + '</button>'
            + '<div class="territory-map-legend-body">'
            + '<div class="territory-map-legend-desc">' + escapeHtml(modeDescription(mode)) + '</div>'
            + (mode !== 'coverage' && mode !== 'detail' ? '<div class="territory-map-legend-scale"><span>' + escapeHtml(minText) + '</span><i class="territory-map-legend-dot territory-map-legend-dot-small"></i><i class="territory-map-legend-dot territory-map-legend-dot-large"></i><span>' + escapeHtml(maxText) + '</span></div>' : '')
            + '<div class="territory-map-color-keys">' + colorsHtml + '</div>'
            + (leadersHtml ? '<div class="territory-map-legend-clients">' + leadersHtml + '</div>' : '')
            + '</div>';

        var toggle = legend.querySelector('.territory-map-legend-toggle');
        if (toggle) {
            toggle.addEventListener('click', function () {
                var nextExpanded = legend.getAttribute('data-expanded') !== 'true';
                legend.setAttribute('data-expanded', nextExpanded ? 'true' : 'false');
                toggle.setAttribute('aria-expanded', nextExpanded ? 'true' : 'false');
                var helper = toggle.querySelector('small');
                var icon = toggle.querySelector('.territory-map-legend-toggle-icon');
                if (helper) helper.textContent = nextExpanded ? 'Ocultar leyenda' : 'Ver leyenda';
                if (icon) icon.textContent = nextExpanded ? '−' : '+';
            });
        }
    }

    function darkMapStyles() {
        return [
            { elementType: 'geometry', stylers: [{ color: '#1d242d' }] },
            { elementType: 'labels.text.stroke', stylers: [{ color: '#1d242d' }] },
            { elementType: 'labels.text.fill', stylers: [{ color: '#aeb6c2' }] },
            { featureType: 'administrative.country', elementType: 'geometry.stroke', stylers: [{ color: '#6b7280' }] },
            { featureType: 'administrative.province', elementType: 'geometry.stroke', stylers: [{ color: '#424b57' }] },
            { featureType: 'landscape', elementType: 'geometry', stylers: [{ color: '#202832' }] },
            { featureType: 'poi', stylers: [{ visibility: 'off' }] },
            { featureType: 'road', stylers: [{ visibility: 'off' }] },
            { featureType: 'transit', stylers: [{ visibility: 'off' }] },
            { featureType: 'water', elementType: 'geometry', stylers: [{ color: '#05070b' }] },
            { featureType: 'water', elementType: 'labels.text.fill', stylers: [{ color: '#4b5563' }] }
        ];
    }

    function renderMap(container, rawPoints) {
        var mapEl = container.querySelector('[data-map-canvas]');
        if (!mapEl) return;

        var points = rawPoints.filter(function (point) {
            var lat = toNumber(point.lat);
            var lng = toNumber(point.lng);
            return Number.isFinite(lat) && Number.isFinite(lng) && !(lat === 0 && lng === 0);
        });

        if (!points.length) {
            setMessage(container, 'No hay clientes con coordenadas validas para visualizar el mapa BI. Ejecuta el backfill geografico.');
            return;
        }

        var bounds = new google.maps.LatLngBounds();
        points.forEach(function (point) {
            bounds.extend({ lat: toNumber(point.lat), lng: toNumber(point.lng) });
        });

        var mapOptions = {
            center: { lat: toNumber(points[0].lat), lng: toNumber(points[0].lng) },
            zoom: 4,
            mapTypeControl: false,
            streetViewControl: true,
            fullscreenControl: true,
            gestureHandling: 'cooperative',
            zoomControl: true,
            styles: darkMapStyles()
        };

        var mapId = container.getAttribute('data-map-id') || '';
        if (mapId) {
            mapOptions.mapId = mapId;
            delete mapOptions.styles;
        }

        var map = new google.maps.Map(mapEl, mapOptions);
        var infoWindow = new google.maps.InfoWindow();
        var markers = [];
        var activeMode = DEFAULT_MODE;

        function applyMode(mode) {
            activeMode = mode || DEFAULT_MODE;
            clearMarkers(markers);
            setButtonState(container, activeMode);
            setTitle(container, MODE_LABELS[activeMode] || MODE_LABELS.value);

            var range = valueRange(points, activeMode);
            points.forEach(function (point) {
                var marker = createMarker(point, map, infoWindow, activeMode, range);
                if (marker) markers.push(marker);
            });

            renderLegend(container, mapEl, points, activeMode, range);
            setMessage(container, points.length + ' clientes geolocalizados visibles · ' + modeDescription(activeMode));
        }

        container.querySelectorAll('[data-territory-map-mode]').forEach(function (button) {
            button.addEventListener('click', function () {
                applyMode(button.getAttribute('data-territory-map-mode'));
            });
        });

        if (points.length === 1) {
            map.setCenter(bounds.getCenter());
            map.setZoom(12);
        } else {
            map.fitBounds(bounds, 56);
        }

        applyMode(DEFAULT_MODE);
    }

    function init(root) {
        root = root || document;
        var container = root.querySelector('[data-customer-territory-map]');
        if (!container || container.dataset.mapInitialized === VERSION) return;
        container.dataset.mapInitialized = VERSION;

        var key = container.getAttribute('data-google-key') || '';
        var points = getPoints();

        if (!key) {
            setMessage(container, 'Mapa interactivo pendiente: configura GOOGLE_MAPS_BROWSER_KEY. El listado territorial sigue disponible.');
            return;
        }

        loadGoogleMaps(key, function () {
            renderMap(container, points);
        }, function (message) {
            setMessage(container, message);
            console.error('[customer-territory-map] ' + message);
        });
    }

    window.ICY_CUSTOMER_TERRITORY_MAP = {
        version: VERSION,
        init: init
    };

    if (document.readyState === 'loading') {
        document.addEventListener('DOMContentLoaded', function () { init(document); });
    } else {
        init(document);
    }

    document.addEventListener('icy:spa-render', function (event) {
        init(event.target || document);
    });
})();
