package performa.orm;

import java.util.*;
import oneit.logging.LoggingArea;
import oneit.objstore.StorageException;
import oneit.objstore.rdbms.filters.EqualsFilter;
import oneit.objstore.rdbms.filters.IsNotNullFilter;
import oneit.objstore.rdbms.filters.NotEqualsFilter;
import oneit.utils.filter.CollectionFilter;
import oneit.utils.filter.Filter;
import oneit.utils.math.NullArith;
import oneit.utils.math.Rounding;
import oneit.utils.parsers.FieldException;
import performa.orm.types.*;
import performa.utils.AnalysisEngine;


public class JobApplication extends BaseJobApplication
{
    private static final long   serialVersionUID    = 0L;
    public  static LoggingArea  LOG                 = LoggingArea.createLoggingArea("JobApplication");
    
    // This constructor should not be called
    public JobApplication ()
    {
        // Do not add any code to this, always put it in initialiseNewObject
    }

    
    public static JobApplication createNewApplication(Candidate candidate, Job job) throws StorageException, FieldException
    {
        JobApplication  jobApplication  =   createJobApplication(job.getTransaction());
        
        jobApplication.setCandidate(candidate);
        jobApplication.setJob(job);
        
        return jobApplication;
    }
    
    
    public boolean createAssessmentCriteriaObjects() throws FieldException
    {
        boolean safeRedirect = false;

        if(isIncludeAssessmentCriteria())
        {
            for(AssessmentCriteria assessmentCriteria : getJob().getAssessmentCriteriasSet())
            {
                boolean available   = false;
                
                for(AssessmentCriteriaAnswer answer : getAssessmentCriteriaAnswersSet())
                {
                    if(assessmentCriteria.equals(answer.getAssessmentCriteria()))
                    {
                        available = true;
                        break;
                    }
                }
                
                if(!available)
                {
                    AssessmentCriteriaAnswer    answer  =   AssessmentCriteriaAnswer.createAssessmentCriteriaAnswer(getTransaction());

                    addToAssessmentCriteriaAnswers(answer);
                    assessmentCriteria.addToAnswers(answer);
                    safeRedirect = true;
                }
            }
        }
        
        return safeRedirect;    
    }
    
    
    public boolean createCultureCriteriaObjects() throws FieldException
    {
        boolean     safeRedirect    = false;
        Candidate   candidate       = getCandidate();
        
        //to skip culture test
        if(cultureCompleted())
        {
            return safeRedirect;
        }
        
        for(CultureCriteria cultureCriteria : getJob().getCultureCriteriasSet())
        {
            boolean available   = false;

            for(CultureCriteriaAnswer answer : getCandidate().getCultureCriteriaAnswersSet())
            {
                if(cultureCriteria.getCultureElement().equals(answer.getCultureElement()))
                {
                    available = true;
                    break;
                }
            }

            if(!available)
            {
                CultureCriteriaAnswer   answer  =   CultureCriteriaAnswer.createCultureCriteriaAnswer(getTransaction());

                candidate.addToCultureCriteriaAnswers(answer);
                answer.setCultureElement(cultureCriteria.getCultureElement());

                safeRedirect = true;
            }
        }
        
        return safeRedirect;    
    }
    
    
    public boolean initAssessmentAnswers(List<Question> questions) throws StorageException, FieldException
    {
        boolean         redirect        =   false;
        List<Question>  allQuestions    =   new ArrayList<>();
        Candidate       candidate       =   getCandidate();
        
        for(Question question : questions)
        {
            allQuestions.add(question);
            
            if(question.getRightQuestion() != null)
            {
                allQuestions.add(question.getRightQuestion());
            }
        }
        
        for(Question question : allQuestions)            
        {
            boolean available   = false;

            for(Answer answer : candidate.getProfileAssessmentAnswersSet())
            {
                if(question.equals(answer.getQuestion()))
                {
                    available = true;
                    break;
                }
            }

            if(!available)
            {
                Answer  answer  =   Answer.createAnswer(getTransaction());
            
                candidate.addToProfileAssessmentAnswers(answer);
                answer.setQuestion(question);                
                redirect    =   true;
            }
        } 
        
        return redirect;
    }
  
    
    public Answer getAnswerForQuestion(Question question) throws FieldException
    {
        Filter  filter  =   Answer.SearchByAll().andQuestion(new EqualsFilter<>(question));
        
        return CollectionFilter.getFirstMatch(getCandidate().getProfileAssessmentAnswersSet(), filter);
    }
    
    
    public Collection<AssessmentCriteriaAnswer> getACAnswersByType(CriteriaType criteriaType)
    {
        Filter  filter  =   AssessmentCriteriaAnswer.SearchByCriteriaType().byCriteriaType(criteriaType);

        return  CollectionFilter.filter(getAssessmentCriteriaAnswersSet(), filter);
    }

    
    public boolean selectionCompleted() //req   
    {
        if(getJob()!=null && getJob().getIncludeAssessmentCriteria()!=Boolean.TRUE)
        {
            return Boolean.TRUE;
        }
        
        int allAnswersCount =   getAssessmentCriteriaAnswersCount();
        
        if(allAnswersCount == getJob().getAssessmentCriteriasCount())
        {
            Filter      filter          =   AssessmentCriteriaAnswer.SearchByAll().andAnswer(new IsNotNullFilter<>());
            Collection  selectedAnswers =   pipelineJobApplication().toAssessmentCriteriaAnswers(filter).vals();

            return (selectedAnswers.size() == allAnswersCount);
        }
        
        return false;
    }
       
    
    public boolean cultureCompleted()
    {
        return getCandidate().cultureCompleted(getJob());
    }
    
    
    public boolean assessmentCompleted() //role
    {
        return getCandidate().assessmentCompleted(getJob());
    }
    
    
    public int getActualQuestionNumber()
    {
        return getCandidate().pipelineCandidate().toProfileAssessmentAnswers().uniqueVals().size() + 1;
    }
    
    
    public int getQuestionNumber()
    {
        return getCandidate().pipelineCandidate().toProfileAssessmentAnswers().uniqueVals().size() 
                - getCandidate().pipelineCandidate().toProfileAssessmentAnswers().toQuestion().toRightQuestion().uniqueVals().size();
    }
    
    
    public boolean isIncludeAssessmentCriteria()
    {
        return getJob() != null && isTrue(getJob().getIncludeAssessmentCriteria());
    }
    
    
//    TODO: Fix these hard coded values
    @Override
    public Integer getOverallSuitability()
    {
        return 1;
    }
    
    
    public Double getJobMatchPercentage() //ROLE
    {
        return AnalysisEngine.getRoleFitSuitability(getCandidate(), getJob().getLevel()).get(null);
    }
    
    
    public int getCulturePercentage()
    {
        return AnalysisEngine.getCultureFit(getCandidate().getCultureCriteriaAnswersSet(), getJob()).get(null).intValue();
    }
    
    
    public int getCriteriaPercentage () //REQ
    {
        return AnalysisEngine.getRequirementFit(getAssessmentCriteriaAnswersSet()).get(null).intValue();
    }
    
    
    public List<AppProcessOption> getValidProcessOptions()
    {
        List<AppProcessOption>  options = new ArrayList<>();
        
        if(getApplicationStatus() == ApplicationStatus.SUBMITTED)
        {
            options.add(AppProcessOption.TO_SHORTLIST);
        }
        else if(getApplicationStatus() == ApplicationStatus.SHORTLISTED)
        {
            options.add(AppProcessOption.REMOVE_FROM_SHORTLIST);
        }
        
        return options;
    }
    
    
    public String getApplicantStatusStr()
    {
        return getApplicationStatus().getDescription();
    }
    
    
    public List<ApplicationStatus> getAvailableStatuses()
    {
        List<ApplicationStatus>  statuses = new ArrayList<>();
        
        statuses.add(ApplicationStatus.SUBMITTED);
        statuses.add(ApplicationStatus.SHORTLISTED);
        statuses.add(ApplicationStatus.UNSUITABLE);
        
        return statuses;
    }
        
    
    public Collection<JobApplication> getAllSubmittedApplicationsByCandidate()
    {
        Filter  filter  =   JobApplication.SearchByAll().andApplicationStatus(new NotEqualsFilter<>(ApplicationStatus.DRAFT));
        
        return  CollectionFilter.filter(getCandidate().getJobApplicationsSet(), filter);
    }
 
    
    public Set<Answer> getCompletedAnswers()
    {
        return getCandidate().getProfileAssessmentAnswersSet();
    }
    
    
    public Set<FactorClass> getSortedFactorClasses()
    {
        Set<FactorClass>    factorClasses       =   new LinkedHashSet<>();
        Set<FactorClass>    levelFactorClasses  =   pipelineJobApplication().toJob().toLevel().toLevelClassCriterias().toFactorClass().uniqueVals();
        
        for(FactorClass factorClass : FactorClass.getFactorClassArray())    //getFactorClassArray returns Factor Classes sorted by SortOrder
        {
            if(levelFactorClasses.contains(factorClass))
            {
                factorClasses.add(factorClass);
            }
        }
        return factorClasses;
    }
    
    
    //to get pending time to complete job application
    public Integer  getRemainingTime()
    {
        //req-07 min
        //cul-07 min
        //req-26 min
        
        int remainingTime   =   0;
        
        //REQ
        if(getJob()!=null && getJob().getIncludeAssessmentCriteria()==Boolean.TRUE)
        {
            if(!selectionCompleted())
            {
                remainingTime   +=  7;
            }
        }
        
        if(!cultureCompleted())
        {
            remainingTime   +=  7;
        }
        
        //ROLE
        remainingTime   +=  getRoleTestRemainingTime() ;
        
        if(!assessmentCompleted())
        {
            remainingTime   += 6;
        }
        
        return remainingTime;
    }
    
    
    //to get remaining time for role test
    public Integer getRoleTestRemainingTime()
    {
        int remainingTime   =   20;
        
        if(assessmentCompleted())
        {
            remainingTime   -=  20;
        }
        else //partially completed test for role
        {
            int allAnswersCount =   getJob().getAllLeftQuestions(Arrays.asList(Question.searchAll(getTransaction()))).size(); 

            if(allAnswersCount > 0)
            {
                Filter      filter          =   Answer.SearchByAll().andAnswerNo(new IsNotNullFilter<>());
                Collection  selectedAnswers =   getCandidate().pipelineCandidate().toProfileAssessmentAnswers(filter).vals();

                if(selectedAnswers!=null && selectedAnswers.size()>0)
                {
                    Double  answerrate  =   NullArith.divide(selectedAnswers.size(), allAnswersCount);
                    
                    remainingTime   -=  Rounding.roundDouble( NullArith.multiply(answerrate, 20), 0);
                }
            }
        }
        
        return remainingTime;
    }
}