package br.gov.servicos.destaques;

import br.gov.servicos.config.ServicosDestaqueConfig;
import br.gov.servicos.piwik.PiwikClient;
import br.gov.servicos.piwik.PiwikPage;
import br.gov.servicos.servico.ServicoRepository;
import br.gov.servicos.v3.schema.ServicoXML;
import lombok.experimental.FieldDefaults;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Sort;
import org.springframework.stereotype.Service;

import java.util.List;
import java.util.Objects;
import java.util.Optional;
import java.util.stream.Stream;

import static java.util.Comparator.comparing;
import static java.util.stream.Collectors.toList;
import static java.util.stream.Stream.concat;
import static java.util.stream.Stream.empty;
import static lombok.AccessLevel.PRIVATE;
import static org.springframework.data.domain.Sort.Direction.DESC;

@Slf4j
@Service
@FieldDefaults(level = PRIVATE, makeFinal = true)
public class ServicosEmDestaque {

    ServicoRepository servicos;

    ServicosDestaqueConfig destaques;

    PiwikClient piwikClient;

    Boolean destaquesAutomaticos;

    @Autowired
    public ServicosEmDestaque(
            ServicoRepository servicos,
            ServicosDestaqueConfig destaques,
            PiwikClient piwikClient,
            @Value("${flags.destaques.automaticos}") Boolean destaquesAutomaticos
    ) {
        this.servicos = servicos;
        this.destaques = destaques;
        this.piwikClient = piwikClient;
        this.destaquesAutomaticos = destaquesAutomaticos;
    }

    public List<ServicoXML> servicos(int quantidade) {
        if (destaquesAutomaticos) {
            return completaSevicosAteOLimite(
                    concat(servicosMaisAcessados(),
                            buscaDestaquesSeNecessario()), quantidade);
        }

        return completaSevicosAteOLimite(buscaDestaquesSeNecessario(), quantidade);
    }

    private Stream<ServicoXML> buscaDestaquesSeNecessario() {
        if (destaques.getServicos().isEmpty())
            return empty();

        return destaques.getServicos().stream()
                .map(servicos::findOne)
                .filter(Objects::nonNull);
    }

    private List<ServicoXML> completaSevicosAteOLimite(Stream<ServicoXML> servicosBase, int quantidade) {
        PageRequest pagina = new PageRequest(0, quantidade, new Sort(DESC, "nome"));

        Stream<ServicoXML> outrosServicos = servicos.findAll(pagina).getContent()
                .stream()
                .filter(s -> !destaques.getServicos().contains(s.getId()));

        return concat(servicosBase, outrosServicos)
                .limit(quantidade)
                .collect(toList());
    }

    private Stream<ServicoXML> servicosMaisAcessados() {
        log.debug("Piwik: listando servi├žos mais acessados...");

        Stream<ServicoXML> servicos = piwikClient.getPageUrls("week", "yesterday").stream()
                .sorted(comparing(PiwikPage::getUniqueVisitors))
                .map(PiwikPage::getIdServico)
                .filter(Optional::isPresent)
                .map(Optional::get)
                .distinct()
                .map(this.servicos::findOne)
                .filter(Objects::nonNull);

        log.debug("Piwik: servi├žos mais acessados obtidos");
        return servicos;
    }
}