package com.telephoners.krakyournet.ctf.repositories;

import com.telephoners.krakyournet.ctf.beans.Flag;
import com.telephoners.krakyournet.ctf.beans.User;
import com.telephoners.krakyournet.ctf.beans.tasks.Task;
import com.telephoners.krakyournet.ctf.core.HashValidator;
import com.telephoners.krakyournet.ctf.helpers.DBObjectUtils;
import javafx.util.Pair;
import org.mongodb.morphia.Datastore;

import javax.inject.Inject;
import javax.inject.Singleton;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

@Singleton
public class TasksRepository extends Repository<Task>
{
    private Datastore datastore;
    private UsersRepository usersRepository;
    private HashValidator hashValidator;

    @Inject
    public TasksRepository(Datastore datastore,
                           UsersRepository usersRepository,
                           HashValidator hashValidator)
    {
        super(datastore);
        this.datastore = datastore;
        this.usersRepository = usersRepository;
        this.hashValidator = hashValidator;
    }

    public Task getByLevel(int level)
    {
        return datastore.createQuery(Task.class)
                .filter("level", level)
                .get();
    }

    public List<Task> getAllPublic()
    {
        return datastore.createQuery(Task.class)
                .retrievedFields(true, DBObjectUtils.getPublicFields(Task.class))
                .asList();
    }

    public Map<Integer, List<String>> getUserFlagsHashes(String username)
    {
        return getAll().stream()
                .collect(Collectors.toMap(
                        Task::getLevel,
                        task -> task.getFlags().stream()
                                .map(flag -> hashValidator.calculateHashValue(usersRepository.getUserByName(username), flag.getValue()))
                                .collect(Collectors.toList())
                ));
    }

    public Pair<Task, Flag> getTaskFlagPairByHashValue(User user, String userHash, int taskLevel)
    {
        Flag matchedFlag = getByLevel(taskLevel).getFlags().stream()
                .filter(flag -> hashValidator.calculateHashValue(user, flag.getValue()).equals(userHash))
                .findFirst()
                .get();
        return new Pair<>(getByLevel(taskLevel), matchedFlag);
    }
}