package dendrarium.core.beans;

import dendrarium.core.entities.Answer;
import dendrarium.core.entities.Packet;
import dendrarium.core.entities.TaskBusinessProcess;
import dendrarium.core.entities.User;
import java.io.Serializable;
import java.util.List;
import org.hibernate.Session;
import org.jboss.seam.annotations.In;
import org.jboss.seam.annotations.Logger;
import org.jboss.seam.annotations.Name;
import org.jboss.seam.annotations.RaiseEvent;
import org.jboss.seam.faces.FacesMessages;
import org.jboss.seam.log.Log;

/**
 * Odpowiada za przypisywanie zadan dendrologom
 *
 * @author Piotr Achinger <piotr.achinger at gmail.com>
 */
@Name("taskAssigner")
public class TaskAssigner implements Serializable {

    @Logger
    Log log;

    @In
    Session session;

    @In
    FacesMessages facesMessages;

    @RaiseEvent("tbpchangestate")
    public boolean assignTo(User user) {
        List<TaskBusinessProcess> tbpList;
        TaskBusinessProcess tbp = null;
        user = (User) session.merge(user);
        int komu;

        // sprawdz ze user jest dendrologiem

        Long ileDoPotwierdzenia = (Long) session.getNamedQuery("myNeedConfNum1").setParameter("user", user).uniqueResult()
                + (Long) session.getNamedQuery("myNeedConfNum2").setParameter("user", user).uniqueResult();
        Long ileWOpracowaniu = (Long) session.getNamedQuery("myNotAccepted1").setParameter("user", user).uniqueResult()
                + (Long) session.getNamedQuery("myNotAccepted2").setParameter("user", user).uniqueResult();
        if (ileDoPotwierdzenia + ileWOpracowaniu > 30) {
            log.info("No task assigned to user " + user + ": too many tasks to complete");
            String message = "Nie możesz pobrać nowych akapitów, ponieważ masz jeszcze ";
            if (ileWOpracowaniu > 0) {
                message += ileWOpracowaniu + " zdań w opracowaniu";
                if (ileWOpracowaniu > 0)
                    message += " i ";
            }
            if (ileDoPotwierdzenia > 0) {
                message += ileDoPotwierdzenia + " konfliktów do potwierdzenia";
            }
            message += '.';
            facesMessages.add(message);
            return false;
        }

        out:
        {

            // select done_clean where po stronie done nie jest user

            tbpList = session.createQuery("from TaskBusinessProcess tbp where tbp.current = TRUE and tbp.index = 0 and tbp.state = dendrarium.core.entities.TaskBusinessProcessState.DONE_CLEAN and tbp.user1Answer.user != :user order by tbp.packet.urbanizacja").
                    setParameter("user", user).setMaxResults(1).list();
            if (!tbpList.isEmpty()) {
                tbp = tbpList.get(0);
                komu = 2;
                break out;
            }

            // select inprogress_clean po stronie inp nie user
            tbpList = session.createQuery("from TaskBusinessProcess tbp where tbp.current = TRUE and tbp.index = 0 and tbp.state = dendrarium.core.entities.TaskBusinessProcessState.INPROGRESS_CLEAN and tbp.user1Answer.user != :user order by tbp.packet.urbanizacja").
                    setParameter("user", user).setMaxResults(1).list();
            if (!tbpList.isEmpty()) {
                tbp = tbpList.get(0);
                komu = 2;
                break out;
            }

            tbpList = session.createQuery("from TaskBusinessProcess tbp where tbp.current = TRUE and tbp.index = 0 and tbp.state = dendrarium.core.entities.TaskBusinessProcessState.CLEAN order by tbp.packet.urbanizacja").
                    setMaxResults(1).list();
            if (!tbpList.isEmpty()) {
                tbp = tbpList.get(0);
                komu = 1;
                break out;
            }

            log.info("No task to assign to user " + user);
            facesMessages.add("Brak zadania do przypisania");
            return false;
        }

        /* chyba jednak nie na tym polega problem */
        if (tbp.getUser2Answer() != null) {
            log.info("PRÓBA PODWÓJNEGO PRZYPISANIA ZADANIA!!! id zadania: " + tbp.getId() +
                    " tbp_state: " + tbp.getState().name() + " user: " + user.getUsername());
            tbp.updateState();
            return assignTo(user);
        }

        /* raczej na tym */
        List<Answer> ansList = session.createQuery("from Answer a where taskBusinessProcess = :tbp and taskBusinessProcess.user1Answer != a order by id").
                setParameter("tbp", tbp).list();
        if (!ansList.isEmpty()) {
            log.info("PRÓBA PODWÓJNEGO PRZYPISANIA ZADANIA!!! (dziwny null na user2) id zadania: " +
                    tbp.getId() + " user: " + user.getUsername());
            tbp.setUser2Answer(ansList.get(0));
            ansList.get(0).setAccepted(false); // trzeba, bo inaczej może się nie zrobić autoakceptacja
            ansList.get(0).getTaskBusinessProcess().updateState();
            // najprawdopodobniej lista miała jeden element, więc to tylko na wszelki wypadek
            for (int i = 1; i < ansList.size(); i++)
                session.delete(ansList.get(i));
            tbp.updateState();
            return assignTo(user);
        }

        Packet packet = tbp.getPacket();

        assignPacket(packet, komu, user);

        return true;
    }

    public void assignPacket(Packet packet, int komu, User user) {
        List<TaskBusinessProcess> tasks = session.createQuery("from TaskBusinessProcess tbp where tbp.current = TRUE and tbp.packet = :packet").setEntity("packet", packet).list();

        for (TaskBusinessProcess tbp : tasks) {
            assignTask(tbp, komu, user);
        }
    }

    public void assignTask(TaskBusinessProcess tbp, int komu, User user) {
        Answer answer = new Answer(user, tbp);
        session.persist(answer);
        
        /* jeśli jakoś przeszło przez poprzednie zabezpieczenia (ale chyba się to nie zdarzy) */
        if (tbp.getUser2Answer() != null) {
            log.info("PRÓBA PODWÓJNEGO PRZYPISANIA ZADANIA W assignTask!!! id zadania: " + tbp.getId() +
                    " tbp_state: " + tbp.getState().name() + " user: " + user.getUsername());
            tbp.updateState();
            return;
        }

        if (komu == 1) {
            tbp.setUser1Answer(answer);
        } else if (komu == 2) {
            tbp.setUser2Answer(answer);
        }
        tbp.updateState();

        log.info("HISTORIA: Assigned task " + tbp.getId() + " to " + user + " as user #" + komu);
        log.info(answer.info());
        log.info(tbp.info());
        facesMessages.add("Przypisano zadanie #"+ (tbp.getIndex()+1) +" z paczki '" + tbp.getPacket().getName() + "'");
        session.merge(tbp);
        session.flush();
    }

//    public boolean assignNext(Answer answer) {
//
//        answer = (Answer) session.merge(answer);
//
//        Integer rozmiarPaczki = answer.getTaskBusinessProcess().getPacket().getTasks().size();
//
//        if (answer.getTaskBusinessProcess().getIndex() == rozmiarPaczki - 1) {
//            /* ostatni w paczce */
//            facesMessages.add("Ukończono paczkę '" + answer.getTaskBusinessProcess().getPacket().getName() + "'");
//            return false;
//        } else {
//            Integer index = answer.getTaskBusinessProcess().getIndex();
//
//            TaskBusinessProcess tbp = answer.getTaskBusinessProcess().getPacket().getTasks().get(index + 1);
//
//            if ((tbp.getUser1Answer() != null && tbp.getUser1Answer().getUser().getUsername().equals( answer.getUser().getUsername()) )
//                    || (tbp.getUser2Answer() != null && tbp.getUser2Answer().getUser().getUsername().equals( answer.getUser().getUsername())) ) {
//                /* juz ma nastepne zadanie, czyli np. anulowal i zrobil znowu */
//
//                return false;
//            }
//
//            Answer newAnswer = new Answer(answer.getUser(), tbp);
//            if (tbp.getUser1Answer() == null) {
//                tbp.setUser1Answer(newAnswer);
//            } else {
//                tbp.setUser2Answer(newAnswer);
//            }
//
//            session.persist(newAnswer);
//            tbp.updateState();
//
//            facesMessages.add("Przypisano kolejne (" + (index + 2) + ") zadanie z paczki '" + tbp.getPacket().getName() + "'");
//            return true;
//        }
//    }
}
