package pt.utl.ist.scripts.runOnce.candidacy;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;

import net.sourceforge.fenixedu.domain.Attends;
import net.sourceforge.fenixedu.domain.CurricularCourse;
import net.sourceforge.fenixedu.domain.Enrolment;
import net.sourceforge.fenixedu.domain.EntryPhase;
import net.sourceforge.fenixedu.domain.ExecutionCourse;
import net.sourceforge.fenixedu.domain.ExecutionDegree;
import net.sourceforge.fenixedu.domain.ExecutionSemester;
import net.sourceforge.fenixedu.domain.ExecutionYear;
import net.sourceforge.fenixedu.domain.Shift;
import net.sourceforge.fenixedu.domain.StudentCurricularPlan;
import net.sourceforge.fenixedu.domain.candidacy.CandidacySituationType;
import net.sourceforge.fenixedu.domain.candidacy.StudentCandidacy;
import net.sourceforge.fenixedu.domain.candidacy.degree.ShiftDistributionEntry;
import net.sourceforge.fenixedu.domain.student.Registration;
import pt.utl.ist.scripts.commons.AtomicScript;

public class FixFirstCycleStudentCandidaciesWithoutAttends extends AtomicScript {

    private final EntryPhase entryPhase;

    public FixFirstCycleStudentCandidaciesWithoutAttends(final EntryPhase phase) {
        this.entryPhase = phase;
    }

    public static void main(String[] args) {
        processWriteTransaction(new FixFirstCycleStudentCandidaciesWithoutAttends(EntryPhase.FIRST_PHASE));
        System.exit(0);
    }

    @Override
    protected void run() throws Exception {

        for (final ExecutionDegree executionDegree : ExecutionYear.readCurrentExecutionYear().getExecutionDegreesSet()) {
            if (executionDegree.hasAnyShiftDistributionEntries()) {
                logger.info("\n[EXECUTION_DEGREE][NAME]" + executionDegree.getDegreeCurricularPlan().getName()
                        + " [DEGREE_TYPE] " + executionDegree.getDegree().getDegreeType().getName());

                final List<StudentCandidacy> studentCandidacies = new ArrayList<StudentCandidacy>();

                for (final StudentCandidacy studentCandidacy : executionDegree
                        .getFirstCycleCandidacies(CandidacySituationType.REGISTERED)) {
                    if (studentCandidacy.getEntryPhase() != null && studentCandidacy.getEntryPhase().equals(entryPhase)
                            && !studentCandidacy.getRegistration().hasAnyShifts()) {
                        studentCandidacies.add(studentCandidacy);
                    }
                }

                Collections.sort(studentCandidacies, STUDENT_CANDIDACIES_COMPARATOR);
                for (final StudentCandidacy studentCandidacy : studentCandidacies) {
                    final Registration registration = studentCandidacy.getRegistration();
                    final String istUsername = registration.getPerson().getIstUsername();

                    logger.error("[PERSON][IST_USERNAME] " + istUsername + " [REGISTRATED_STATE_DATE] "
                            + studentCandidacy.getActiveCandidacySituation().getSituationDate());

                    associateShiftsFor(registration, executionDegree);
                }
            }
        }
    }

    static final private Comparator<StudentCandidacy> STUDENT_CANDIDACIES_COMPARATOR = new Comparator<StudentCandidacy>() {
        @Override
        public int compare(StudentCandidacy o1, StudentCandidacy o2) {
            int result =
                    o1.getActiveCandidacySituation().getSituationDate()
                            .compareTo(o2.getActiveCandidacySituation().getSituationDate());
            if (result == 0) {
                result = o1.getRegistration().getNumber().compareTo(o2.getRegistration().getNumber());
            }
            if (result == 0) {
                result = o1.getExternalId().compareTo(o2.getExternalId());
            }
            return (result != 0) ? result : o1.getPerson().getName().compareTo(o2.getPerson().getName());
        }
    };

    protected void associateShiftsFor(final Registration registration, ExecutionDegree executionDegree) {
        ExecutionYear executionYear = executionDegree.getExecutionYear();
        if (executionDegree.getExecutionYear().hasShiftDistribution()) {
            for (final ShiftDistributionEntry shiftEntry : executionDegree.getNextFreeShiftDistributions()) {
                shiftEntry.setDistributed(Boolean.TRUE);
                shiftEntry.getShift().addStudents(registration);
                correctExecutionCourseIfNecessary(registration, shiftEntry.getShift());
            }
        }
    }

    private void correctExecutionCourseIfNecessary(Registration registration, Shift shift) {

        final StudentCurricularPlan studentCurricularPlan = registration.getActiveStudentCurricularPlan();
        final ExecutionCourse finalExecutionCourse = shift.getDisciplinaExecucao();

        for (final CurricularCourse curricularCourse : finalExecutionCourse.getAssociatedCurricularCoursesSet()) {

            final Enrolment enrolment =
                    studentCurricularPlan.getEnrolmentByCurricularCourseAndExecutionPeriod(curricularCourse,
                            ExecutionSemester.readActualExecutionSemester());
            if (enrolment != null) {

                final Attends attends = enrolment.getAttendsFor(ExecutionSemester.readActualExecutionSemester());
                if (attends != null && !attends.isFor(finalExecutionCourse)) {
                    attends.setDisciplinaExecucao(finalExecutionCourse);
                }
                break;
            }
        }
    }

}
