(function () {
    'use strict';

    angular
        .module('contestacaoApp')
        .directive('ferramentaContestacao', ferramentaContestacao);

    ferramentaContestacao.$inject = ['__env', 'gpsFactory', 'FormValidation', '$timeout', '$location', 'statusContestacao', 'utilsFactory', 'mapsSingletonService',
        'userMessages', 'infowindowTemplates', 'ngNotify'];

    /* @ngInject */
    function ferramentaContestacao(__env, gpsFactory, FormValidation, $timeout, $location, statusContestacao, utilsFactory, mapsSingletonService,
        userMessages, infowindowTemplates, ngNotify) {
        return {
            restrict: 'E',
            replace: true,
            require: 'ngModel',
            templateUrl: __env.appPath + 'scripts/components/tools/contestacao/ferramenta-contestacao.directive.html',
            link: link,
            scope: false
        };

        function link(scope, element, attrs, ngModel) {
            /* exports */
            angular.extend(scope.vm, {
                toggleSelecao: toggleSelecao,
                downloadFile: downloadFile,
                removerTrechoSelecionado: removerTrechoSelecionado,
                selecionarPacmanContestado: selecionarPacmanContestado,
                setarValidacaoFormContestacao: setarValidacaoFormContestacao,
                cancelarContestacao: cancelarContestacao,
                onAddFile: onAddFile,
                onRemoveFile: onRemoveFile,
                conversaoLatLng: conversaoLatLng,
                validateFileRules: validateFileRules,
                plotarPacmansContestacao: plotarPacmansContestacao,
                eventoContextoAtual: eventoContextoAtual,
                centralizarPontoMapa: centralizarPontoMapa,
                toogleAccordionJustificativa: toogleAccordion
            });

            scope.vm.listaPontosSelecionados = [];
            scope.vm.algumTrechoSelecionado = '';
            scope.vm.listaArquivosContestacao = [];
            scope.vm.contestacaoMessagem = null;

            let _urlParams = $location.$$search;
            let _selecaoHabilitada = {
                ponto: false,
                pacman: false
            };

            let _buttonToggle = null;
            let idxOverlay = 0;

            scope.$watch('vm.listaNovosArquivosContestacao', onAddFile);

            if (scope.vm.contestacao) inicializacao();

            ngModel.$render = () => { if (ngModel.$modelValue) inicializacao() };

            function inicializacao() {
                plotarPacmansContestacao(ngModel.$modelValue.Contestacao).then(() => {
                    $timeout(() => setarValidacaoFormContestacao(), 500);
                    verificarTrechosSelecionados();
                });
            }

            function onAddFile(newValue) {
                if (newValue && newValue.length) {
                    scope.vm.listaArquivosContestacao.push(...newValue);
                }

                validateFileRules();
            }

            function validateFileRules() {
                let message = null;

                if (scope.vm.listaArquivosContestacao.some(x => !x.name.toLowerCase().includes('.jpg') &&
                    !x.name.toLowerCase().includes('.png') && !x.name.toLowerCase().includes('.pdf') &&
                    !x.name.toLowerCase().includes('.jpeg'))) {
                    message = userMessages.FORMATO_ARQUIVOS_INCORRETOS;
                } else if (scope.vm.listaArquivosContestacao.length > 10) {
                    message = userMessages.QUANTIDADE_ARQUIVOS_EXCEDENTE;
                } else if (scope.vm.listaArquivosContestacao.length > 0 && utilsFactory
                    .convertMebibyteToByte(scope.vm.listaArquivosContestacao
                        .map(x => x.size)
                        .reduce((accumulator, currentValue) => accumulator + currentValue)) >= 5) {
                    message = userMessages.TAMANHO_ARQUIVOS_EXCEDENTE;
                }

                scope.vm.contestacaoMessagem = message;
                if (scope.vm.formContestacao.$valid && message) {
                    setTimeout(() => scope.vm.scrollBottom('#scroll-ferramenta-contestacao'), 10);
                }

                return !message;
            }

            function onRemoveFile(file) {
                scope.vm.listaArquivosContestacao = scope.vm.listaArquivosContestacao.filter(item => item !== file);
                $('#listaArquivosContestacaoInput').prop('value', '');

                validateFileRules();
            }

            function verificarTrechosSelecionados() {
                scope.vm.algumTrechoSelecionado = (scope.vm.contestacao.Contestacao.ContestacaoHistorico || [])
                    .some(x => x.ContestacaoHistoricoTrecho.length) && scope.vm.pacmansContestadosPlotados ?
                    (scope.vm.pacmansContestadosPlotados.some(x => x.ItemSelecionado) ? 'T' : '') : 'T';
            }

            /* seleção de ponto a contestar no mapa */
            function toggleSelecao(tipo) {
                _selecaoHabilitada[tipo] = !_selecaoHabilitada[tipo];
                _buttonToggle = event.target;
                _selecaoHabilitada[tipo] ? habilitaSelecao(tipo) : desabilitaSelecao(tipo)
            }

            function habilitaSelecao(tipo) {
                desabilitaSelecao(tipo === 'pacman' ? 'ponto' : 'pacman');
                _buttonToggle.classList.add('active');

                const map = mapsSingletonService.getMap();
                const options = new InlogMaps.PolygonAlterOptions();
                options.color = '#665200';
                options.fillColor = '#806600';
                map.alterPolygonOptions('setor', options);

                map.addPolygonEvent('setor', InlogMaps.PolygonEventType.Click,
                    tipo === 'ponto' ? habilitaContestacaoPonto : habilitaContestacaoPacman);

                $('#map svg *').addClass('cursor-new-point');
            }

            function desabilitaSelecao(tipo) {
                $(`#contestacao-${tipo}`).removeClass('active');
                _selecaoHabilitada[tipo] = false;

                const map = mapsSingletonService.getMap();
                const options = new InlogMaps.PolygonAlterOptions();
                options.color = '#000';
                options.fillColor = '#000';
                map.alterPolygonOptions('setor', options);
                map.removePolygonEvent('setor', InlogMaps.PolygonEventType.Click);
                map.removeCircles('pacmanContestado');

                map.toggleMarkers(false, 'pacmanContestado', (data) => data.Cumprido === 'T');
                $('#map svg *').removeClass('cursor-new-point');
            }

            function removerTrechoSelecionado(trecho) {
                let idx = scope.vm.listaPontosSelecionados.indexOf(trecho);
                if (idx >= 0) {
                    scope.vm.listaPontosSelecionados.splice(idx, 1);
                }

                removerMarkerTrechoSelecionado(trecho);

                if (!scope.$$phase) {
                    scope.$apply();
                }
            }

            function removerMarkerTrechoSelecionado(trecho) {
                if (trecho.Pacman) {
                    const iconUrl = getIconPacman(false, false, trecho.Sequencia, trecho.Justificado);
                    const options = new InlogMaps.MarkerAlterOptions();
                    options.icon = new InlogMaps.MarkerIcon(iconUrl);

                    mapsSingletonService.getMap().alterMarkerOptions('pacmanContestado', options,
                        (item) => item.CodigoTrecho === trecho.CodigoTrecho);
                } else {
                    mapsSingletonService.getMap().removeOverlays('pontoContestado',
                        (item) => item.Codigo === trecho.Codigo);
                }
            }

            /* -------------- CONTESTAÇÃO POR PONTOS */
            function habilitaContestacaoPonto(event, object) {
                let latlng = event.latlng;

                mapsSingletonService.buscarGeoCodeReverso(latlng)
                    .then((result) => selecionarPonto(result, latlng))
                    .catch(err => console.log(err));
            }

            async function selecionarPonto(result, latlng) {
                const obj = {
                    Rua: result,
                    Latitude: latlng[0],
                    Longitude: latlng[1],
                    Pacman: false,
                    Codigo: idxOverlay++
                };

                scope.vm.listaPontosSelecionados.push(obj);

                adicionarMarkerComBotaoFechar('pontoContestado', obj, `${__env.baseUrl}/${__env.appPath}images/ico_contestado.png`);

                if (!scope.$$phase) {
                    scope.$apply();
                }
            }

            function adicionarMarkerComBotaoFechar(tipo, obj, iconURL) {
                const div = document.createElement('div');
                div.style.position = 'absolute';

                const img = document.createElement('img');
                img.src = iconURL;
                img.style.position = 'absolute';
                img.style.top = '-7px';
                img.style.left = '-7px';
                div.appendChild(img);

                const imgClose = document.createElement('img');
                imgClose.src = `${__env.baseUrl}/${__env.appPath}images/close.svg`;
                imgClose.setAttribute("id", `close-overlay-codigo-${obj.Codigo}`);
                imgClose.style.position = 'absolute';
                imgClose.style.top = '-10px';
                imgClose.style.left = '12px';
                imgClose.style.width = '13px';
                div.appendChild(imgClose);

                const overlayOptions = new InlogMaps.OverlayOptions(div, true);
                overlayOptions.position = [obj.Latitude, obj.Longitude];
                overlayOptions.object = obj;
                overlayOptions.draggable = true;
                overlayOptions.afterEventDragHandler = aoMoverPontoContestado;
                mapsSingletonService.getMap().drawOverlay(tipo, overlayOptions);

                setTimeout(() => document.getElementById(`close-overlay-codigo-${obj.Codigo}`)
                    .addEventListener('click', (event) => {
                        event.stopPropagation();
                        removerTrechoSelecionado(obj);
                    }), 500);
            }

            function aoMoverPontoContestado(event, obj) {
                const idx = scope.vm.listaPontosSelecionados.findIndex(x => x.Codigo === obj.Codigo);

                if (pontoDentroSetor(event)) {
                    mapsSingletonService.buscarGeoCodeReverso(event.latlng).then((result) => {
                        scope.vm.listaPontosSelecionados[idx].Latitude = event.latlng[0];
                        scope.vm.listaPontosSelecionados[idx].Longitude = event.latlng[1];
                        scope.vm.listaPontosSelecionados[idx].Rua = result;

                        if (!scope.$$phase) {
                            scope.$apply();
                        }
                    }).catch(err => console.log(err));
                } else {
                    ngNotify.set('O ponto não deve ser alocado para fora do setor. Estamos redirecionando ele para a ultima posição conhecida.',
                        { type: 'warn', sticky: false });

                    mapsSingletonService.getMap().removeOverlays('pontoContestado', (item) => item.Codigo === obj.Codigo);
                    adicionarMarkerComBotaoFechar('pontoContestado', scope.vm.listaPontosSelecionados[idx],
                        `${__env.baseUrl}/${__env.appPath}images/ico_contestado.png`);
                }
            }

            function pontoDentroSetor(event) {
                let dentro = false;

                scope.vm.camadas.Setor.Areas.forEach((area) => {
                    const path = area.Coordenadas.map(x => [x.Longitude / 1000000, x.Latitude / 1000000]);
                    const point = turf.point([event.latlng[1], event.latlng[0]]);
                    const polygon = turf.polygon([path]);

                    if (turf.booleanPointInPolygon(point, polygon))
                        dentro = true;
                });

                return dentro;
            }

            /* -------------- CONTESTAÇÃO POR PACMANS */
            function habilitaContestacaoPacman(event) {
                const raioCirculo = 100;
                const map = mapsSingletonService.getMap();
                map.toggleMarkers(false, 'pacmanContestado', (data) => data.Cumprido === 'T');
                map.removeCircles('pacmanContestado');

                const options = new InlogMaps.CircleOptions(event.latlng, raioCirculo, 3, true, 0.4);
                options.color = '#000000';
                map.drawCircle('pacmanContestado', options);

                const listaPacmans = [];
                scope.vm.camadas.Pacmans.filter(x => x.Cumprido === 'T').forEach(pacman => {
                    let distanciaPacman = gpsFactory
                        .leiCosenos(event.latlng, [pacman.Latitude / 1000000, pacman.Longitude / 1000000]);

                    if (distanciaPacman <= raioCirculo) {
                        map.toggleMarkers(true, 'pacmanContestado', (data) => data.CodigoTrecho === pacman.Codigo);
                    }
                });
            }

            async function plotarPacmansNaoCumpridos(pacmans) {
                await Promise.all(pacmans.map(async pacman => {
                    let position = [pacman.Latitude / 1000000, pacman.Longitude / 1000000];

                    const options = new InlogMaps.MarkerOptions(position);
                    options.object = {
                        CodigoTrecho: pacman.Codigo,
                        Sequencia: pacman.Sequencia,
                        ItemSelecionado: false,
                        Rota: pacman.SetorRota.Descricao,
                        Cumprido: pacman.Cumprido,
                        Justificado: (pacman.DescricaoJustObservacao != null && pacman.DescricaoJustObservacao.length > 0),
                        Justificativa: pacman.DescricaoJustObservacao
                    };

                    const iconUrl = getIconPacman(false, pacman.Cumprido === 'F', pacman.Sequencia, options.object.Justificado);
                    const iconSize = await mapsSingletonService.getIconSize(iconUrl);
                    options.icon = new InlogMaps.MarkerIcon(iconUrl, iconSize);

                    if (pacman.Cumprido === 'F') {
                        options.addToMap = true;
                        inserirPacmanContestado(pacman.Sequencia, pacman.Codigo, pacman.SetorRota.Descricao, position[0],
                            position[1], options.object.Justificado, pacman.DescricaoJustObservacao);
                    }

                    const type = 'pacmanContestado';
                    mapsSingletonService.getMap().drawMarker(type, options, selecionarTrecho);

                    if (options.object.Justificado) {
                        const condition = (item) => item.CodigoTrecho === pacman.Codigo;
                        mapsSingletonService.getMap().addMarkerEvent(type, InlogMaps.MarkerEventType.MouseOver,
                            (param, obj) => abrirPopupPacman(obj, condition), condition);
                    }
                }));
            }

            function abrirPopupPacman(obj, condition) {
                const type = 'pacmanContestado';
                const options = new InlogMaps.PopupOptions();

                options.marker = type;
                options.conditionMarker = condition;
                options.content = infowindowTemplates.montarInfoWindowJustificativaPacman(obj)
                options.object = obj.CodigoTrecho;

                mapsSingletonService.getMap().drawPopup(type, options);
            }

            async function plotarPacmansContestacao(contestacao) {
                if (contestacao.StatusContestacao === 5 && !scope.vm.contestacaoPonto) {
                    await plotarPacmansNaoCumpridos(scope.vm.camadas.Pacmans);
                } else {
                    (scope.vm.pacmansContestadosPlotados || []).forEach(trecho =>
                        mapsSingletonService.getMap().removeMarkers('pacmanContestadosPlotados',
                            (item) => item.CodigoTrecho === trecho.CodigoTrecho));

                    scope.vm.pacmansContestadosPlotados = [];
                    let historico = contestacao.ContestacaoHistorico;
                    const historicoTrechos = historico && historico.length ? historico[historico.length - 1].ContestacaoHistoricoTrecho : [];

                    if (historicoTrechos.length && contestacao.ContestacaoTrecho.length) {
                        await plotarHistoricoTrecho(historicoTrechos);
                    }

                    verificarTrechosSelecionados();
                }

                scope.vm.toolOpen = 'question';

                if (scope.vm.hideLoading) {
                    scope.vm.hideLoading();
                }
            }

            async function plotarHistoricoTrecho(trechos) {
                await Promise.all(trechos.map(async trecho => {
                    const path = [trecho.ContestacaoTrecho.Latitude / 1000000, trecho.ContestacaoTrecho.Longitude / 1000000];
                    const options = new InlogMaps.MarkerOptions(path, true);
                    const pacman = trecho.ContestacaoTrecho.CodigoTrecho && trecho.ContestacaoTrecho.CodigoTrecho > 0;
                    options.object = {
                        CodigoTrecho: trecho.CodigoTrecho,
                        codigo: trecho.CodigoTrecho,
                        Sequencia: trecho.ContestacaoTrecho.Sequencia,
                        ItemSelecionado: false,
                        Rota: trecho.ContestacaoTrecho.SetorRotaPacman ? trecho.ContestacaoTrecho.SetorRotaPacman.SetorRota.Descricao :
                            trecho.ContestacaoTrecho.Endereco,
                        Pacman: pacman
                    }

                    const iconUrl = !pacman ? `${__env.baseUrl}/${__env.appPath}images/ico_contestado.png` :
                        getIconPacman(false, true, trecho.ContestacaoTrecho.Sequencia, false);
                    const iconSize = await mapsSingletonService.getIconSize(iconUrl);
                    options.icon = new InlogMaps.MarkerIcon(iconUrl, iconSize);
                    mapsSingletonService.getMap().drawMarker('pacmanContestadosPlotados', options);

                    if (scope.vm.pacmansContestadosPlotados.filter((item) =>
                        item.CodigoTrecho === trecho.CodigoTrecho).length === 0) {
                        scope.vm.pacmansContestadosPlotados.push(options.object);
                    }
                }));
            }

            function selecionarPacmanContestado(pacman) {
                revalidarFormContestacao();
                pacman.ItemSelecionado = !pacman.ItemSelecionado;

                let iconUrl = '';
                if (!pacman.Pacman) {
                    iconUrl = pacman.ItemSelecionado ? `${__env.baseUrl}/${__env.appPath}images/ico_contestado-selecionado.png` :
                        `${__env.baseUrl}/${__env.appPath}images/ico_contestado.png`;
                }
                else iconUrl = getIconPacman(pacman.ItemSelecionado, true, pacman.Sequencia, false);

                const options = new InlogMaps.MarkerAlterOptions();
                options.icon = new InlogMaps.MarkerIcon(iconUrl);

                mapsSingletonService.getMap().alterMarkerOptions('pacmanContestadosPlotados', options,
                    (item) => item.CodigoTrecho === pacman.CodigoTrecho);

                verificarTrechosSelecionados();
            }

            function getIconPacman(itemSelecionado, itemContestado, sequencia, justificado) {
                return `${__env.baseUrl}/Setores/SetoresSource/MontarIconePacmanContestacao?itemSelecionado=` +
                    `${itemSelecionado}&itemContestado=${itemContestado}&sequencia=${sequencia}&itemJustificado=${justificado}`;
            }

            function selecionarTrecho(event, trecho) {
                let trechoSelecionado = scope.vm.listaPontosSelecionados.find(item => item.CodigoTrecho === trecho.CodigoTrecho);

                if (!trechoSelecionado) {
                    inserirPacmanContestado(trecho.Sequencia, trecho.CodigoTrecho, trecho.Rota, event.latlng[0],
                        event.latlng[1], trecho.Justificado, trecho.Justificativa);

                    const iconUrl = getIconPacman(false, true, trecho.Sequencia, trecho.Justificado);
                    const options = new InlogMaps.MarkerAlterOptions();
                    options.icon = new InlogMaps.MarkerIcon(iconUrl);

                    mapsSingletonService.getMap().alterMarkerOptions('pacmanContestado', options,
                        (item) => item.CodigoTrecho === trecho.CodigoTrecho);
                }
                else removerTrechoSelecionado(trechoSelecionado);

                if (!scope.$$phase) {
                    scope.$apply();
                }
            }

            function inserirPacmanContestado(sequencia, codigo, rota, lat, lng, justificado, obs) {
                let trecho = scope.vm.listaPontosSelecionados.find(item => item.CodigoTrecho === codigo);

                if (!trecho) {
                    scope.vm.listaPontosSelecionados.push({
                        Trecho: `Trecho ${sequencia}`,
                        Sequencia: sequencia,
                        CodigoTrecho: codigo,
                        Rota: rota,
                        Latitude: lat,
                        Longitude: lng,
                        Pacman: true,
                        Justificado: justificado,
                        Justificativa: obs
                    });
                }
            }

            function cancelarContestacao(limparTudo) {
                desabilitaSelecao('pacman');
                desabilitaSelecao('ponto');

                mapsSingletonService.getMap().removeOverlays('pontoContestado');
                scope.vm.listaPontosSelecionados.forEach(trecho => removerMarkerTrechoSelecionado(trecho));

                if (limparTudo)
                    mapsSingletonService.getMap().removeMarkers('pacmanContestado');

                scope.vm.listaPontosSelecionados = [];

                (scope.vm.pacmansContestadosPlotados || []).forEach(pacman => {
                    pacman.Descricao = '';
                    pacman.CodigoTrechoSelecionado = false;

                    if (pacman.ItemSelecionado) {
                        selecionarPacmanContestado(pacman);
                    }
                });

                if (!scope.vm.validationFormContestacao) return;
                scope.vm.validationFormContestacao.resetControlsValidation();
                scope.vm.validationFormContestacao = null;
                scope.vm.contestacaoMessagem = null;
            }

            function setarValidacaoFormContestacao() {
                if (!scope.vm.contestacao || (scope.vm.validationFormContestacao !== null
                    && scope.vm.validationFormContestacao !== undefined)) return;

                if (scope.vm.contestacao.Contestacao.StatusContestacao !== statusContestacao.RESPONDIDA &&
                    scope.vm.contestacao.Contestacao.StatusContestacao !== statusContestacao.NAO_AVALIADA) {
                    return
                }

                if (scope.vm.formContestacao.$$controls.length === 0) return;

                scope.vm.validationFormContestacao = new FormValidation(scope.vm.formContestacao);
                scope.vm.validationFormContestacao.setControlsValidation();
            }

            function revalidarFormContestacao() {
                scope.vm.formContestacao.$$controls.forEach((control) => {
                    if (control.$name !== '') {
                        control.$viewChangeListeners.forEach((func) => func());
                    }
                });
            }

            function downloadFile(anexo) {
                window.open(`${__env.baseUrl}/Setores/Contestacao/DownloadAnexo?arquivo=${anexo.Anexo}&data=` +
                    `${anexo.DataHora}&codigoContestacao=${scope.vm.contestacao.Contestacao.Codigo}`);
            }

            function conversaoLatLng(coordenada) {
                return coordenada < 90 && coordenada > -90 ? parseInt(coordenada * 1000000) : coordenada;
            }

            function eventoContextoAtual(objeto) {
                let dataUrlFormatada = utilsFactory.formatDate(new Date(_urlParams.dt), 'dd/mm/yyyy');
                let dataRetornoEvento = utilsFactory.formatDate(new Date(objeto.DataExecucao), 'dd/mm/yyyy');

                let codigoUrlSetor = parseInt(_urlParams.codigoSetor);
                let codigoRetornoEvento = objeto.CodigoSetor;

                return dataUrlFormatada === dataRetornoEvento && codigoRetornoEvento === codigoUrlSetor;
            }

            function centralizarPontoMapa(ponto) {
                if (ponto.Pacman) {
                    centralizarPacman(ponto, map);
                } else {
                    centralizarPonto(ponto);
                }
            }

            function centralizarPonto(ponto) {
                const map = mapsSingletonService.getMap();
                const type = 'pontoContestado';
                let condition = (item) => item.Codigo === ponto.Codigo;

                map.setCenter([ponto.Latitude, ponto.Longitude]);
                setarZoom();

                map.removeOverlays(type, condition);
                adicionarMarkerComBotaoFechar('pontoContestado', ponto, `${__env.baseUrl}/${__env.appPath}images/ico_contestado-selecionado.png`);

                setTimeout(() => {
                    map.removeOverlays(type, condition);
                    adicionarMarkerComBotaoFechar('pontoContestado', ponto, `${__env.baseUrl}/${__env.appPath}images/ico_contestado.png`);
                }, 500);
            }

            function centralizarPacman(ponto) {
                let type = 'pacmanContestado';
                let condition = (item) => item.CodigoTrecho === ponto.CodigoTrecho;

                mapsSingletonService.getMap().setCenterMarker(type, condition);
                setarZoom();

                alterMarkerIcon(getIconPacman(true, true, ponto.Sequencia, ponto.Justificado), type, condition);
                setTimeout(() => alterMarkerIcon(getIconPacman(false, true, ponto.Sequencia, ponto.Justificado), type, condition), 500);
            }

            function alterMarkerIcon(iconUrl, type, condition) {
                const options = new InlogMaps.MarkerAlterOptions();
                options.icon = new InlogMaps.MarkerIcon(iconUrl);
                mapsSingletonService.getMap().alterMarkerOptions(type, options, condition);
            }

            function setarZoom() {
                const map = mapsSingletonService.getMap();

                setTimeout(() => {
                    if (map.getZoom() < 18)
                        map.setZoom(18);
                }, 200);
            }

            function toogleAccordion(ponto) {
                let target = $(`#justificativa-trecho-${ponto.CodigoTrecho}`);

                if (target.hasClass('hide'))
                    target.removeClass('hide');
                else target.addClass('hide');
            }
        }
    }
})();
