package br.gov.servicos.editor.frontend;

import br.gov.servicos.editor.servicos.Orgao;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.ObjectReader;
import com.github.slugify.Slugify;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.SneakyThrows;
import lombok.experimental.FieldDefaults;
import lombok.experimental.NonFinal;
import lombok.experimental.Wither;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.core.io.ClassPathResource;
import org.springframework.stereotype.Component;
import org.springframework.web.client.RestTemplate;

import java.util.List;
import java.util.function.Predicate;
import java.util.zip.GZIPInputStream;

import static java.util.stream.Collectors.toList;
import static lombok.AccessLevel.PRIVATE;
import static net.logstash.logback.marker.Markers.append;

@Slf4j
@Component
@FieldDefaults(level = PRIVATE, makeFinal = true)
public class Orgaos implements InitializingBean {

    public static final ClassPathResource RESOURCE = new ClassPathResource("estrutura-organizacional.json.gz");

    RestTemplate rest;
    ObjectReader reader;
    Slugify slugify;

    @NonFinal
    EstruturaOrganizacional estruturaOrganizacional;

    @Autowired
    public Orgaos(RestTemplate rest, ObjectMapper mapper, Slugify slugify) {
        this.rest = rest;
        this.slugify = slugify;
        this.reader = mapper.reader(EstruturaOrganizacional.class);
    }

    @Override
    @SneakyThrows
    public void afterPropertiesSet() throws Exception {
        log.debug("Lendo estrutura organizacional de {}...", RESOURCE);
        estruturaOrganizacional = reader.readValue(new GZIPInputStream(RESOURCE.getInputStream()));
        log.debug("Estrutura organizacional lida com sucesso", RESOURCE);
    }

    @Cacheable("orgaos")
    public List<Orgao> get(String termo) {
        List<Orgao> busca = estruturaOrganizacional.getUnidades()
                .stream()
                .filter(new FiltroDeOrgaos(termo))
                .map(u -> new Orgao().withNome(String.format("%s (%s)", u.getNome().trim(), u.getSigla().trim()))
                        .withId(u.getCodigoUnidade()))
                .sorted((l, r) -> l.getNome().compareTo(r.getNome()))
                .collect(toList());

        log.info(append("orgaos.termo", termo).and(append("orgaos.resultados", busca.size())),
                "Buscando órgãos com termo '{}': {} resultados", termo, busca.size());

        return busca;
    }

    @Data
    @Wither
    @NoArgsConstructor
    @AllArgsConstructor
    public static class EstruturaOrganizacional {
        Servico servico;
        List<Unidade> unidades;
    }

    @Data
    @Wither
    @NoArgsConstructor
    @AllArgsConstructor
    public static class Servico {
        long codigoErro;
        String mensagem;
    }

    @Data
    @Wither
    @NoArgsConstructor
    @AllArgsConstructor
    public static class Unidade {
        String codigoUnidade;
        String codigoUnidadePai;
        String codigoOrgaoEntidade;
        String codigoTipoUnidade;
        String nome;
        String sigla;
        String codigoEsfera;
        String codigoPoder;
        String codigoNaturezaJuridica;
        String codigoSubNaturezaJuridica;
    }

    @FieldDefaults(level = PRIVATE, makeFinal = true)
    private class FiltroDeOrgaos implements Predicate<Unidade> {

        String termo;

        public FiltroDeOrgaos(String termo) {
            this.termo = termo;
        }

        @Override
        public boolean test(Unidade u) {
            return limpa(u.getNome()).contains(limpa(termo)) || limpa(u.getSigla()).contains(limpa(termo));
        }

        private String limpa(String s) {
            return slugify.slugify(s).replace('-', ' ');
        }

    }
}

@@ -2824,33 +2824,8 @@
 l %7B%0A
-        Servico servico;%0A
     
@@ -2956,489 +2956,88 @@
 ass 
-Servico %7B%0A        long codigoErro;%0A        String mensagem;%0A    %7D%0A%0A    @Data%0A    @Wither%0A    @NoArgsConstructor%0A    @AllArgsConstructor%0A    public static class Unidade %7B%0A        String codigoUnidade;%0A        String codigoUnidadePai;%0A        String codigoOrgaoEntidade;%0A        String codigoTipoUnidade;%0A        String nome;%0A        String sigla;%0A        String codigoEsfera;%0A        String codigoPoder;%0A        String codigoNaturezaJuridica;%0A        String codigoSubNaturezaJuridic
+Unidade %7B%0A        String codigoUnidade;%0A        String nome;%0A        String sigl
 a;%0A 

Remove código não utilizado