package performa.utils;

import java.util.HashSet;
import java.util.Set;
import oneit.objstore.ObjectTransaction;
import oneit.objstore.StorageException;
import oneit.objstore.rdbms.filters.EqualsFilter;
import oneit.objstore.rdbms.filters.IsNullFilter;
import oneit.objstore.services.TransactionServices;
import oneit.objstore.services.TransactionTask;
import oneit.utils.NestedException;
import oneit.utils.parsers.FieldException;
import performa.orm.ILOJobTitle;
import performa.orm.Job;
import performa.orm.JobApplication;
import performa.orm.MessageTemplate;
import performa.orm.WorkFlow;
import performa.orm.WorkFlowMessage;
import performa.orm.WorkFlowStage;
import performa.orm.WorkFlowStep;
import performa.orm.WorkFlowTemplate;
import performa.orm.types.ApplicantSource;
import performa.orm.types.ApplicationStatus;
import performa.orm.types.StageType;
import performa.orm.types.StepType;


public class WorkflowDataMigration 
{
    public static void main (final String[] args) throws Exception
    {
        TransactionServices.run(new TransactionTask() {
            @Override
            public void run(ObjectTransaction objTran) throws FieldException, StorageException
            {
                try
                {
                    Job[]   jobs    =   Job.SearchByAll().andWorkFlowTemplate(new IsNullFilter<>()).search(objTran);
                    
                    for(Job job : jobs)
                    {
                        if(job.getILOJobTitle() == null && job.getOccupation() != null)
                        {
                            ILOJobTitle[] titles = ILOJobTitle.SearchByAll().andOccupation(new EqualsFilter<>(job.getOccupation())).search(objTran);
                            
                            if(titles.length > 0)
                            {
                                job.setILOJobTitle(titles[0]);
                            }
                        }
                        
                        if(job.getHiringTeam() == null || job.getILOJobTitle() == null)
                        {
                            continue;
                        }
                        
                        WorkFlowTemplate    wfTemplate  =   WorkFlowTemplate.createWorkFlowTemplate(objTran);
                        
                        wfTemplate.setTemplateName(job.getJobTitle());
                        wfTemplate.setIsSystemGenerated(Boolean.TRUE);
                        wfTemplate.setHiringTeam(job.getHiringTeam());
                        wfTemplate.setRelatedToJob(Boolean.TRUE);
                        job.setWorkFlowTemplate(wfTemplate);
                        
                        int sortOrder       =   0;
                        int stepSortOrder   =   0;
                        
                        MessageTemplate[]   messageTemplates    =   MessageTemplate.SearchByAll().andMessageID(new EqualsFilter<>(job.getHiringTeam().getMessageID())).andIsSystemGenerated(new EqualsFilter<>(Boolean.TRUE)).search(objTran);
                        WorkFlowStage       initialStage        =   createWorkFlowStage(objTran, wfTemplate, "Initial", StageType.INITIAL, sortOrder++);
                        
                        if(job.getDiversityIncluded())
                        {
                            createWorkFlowStep(objTran, initialStage, StepType.DIVERSITY, stepSortOrder++);
                        }
                        
                        if(job.getIncludeAssessmentCriteria())
                        {
                            createWorkFlowStep(objTran, initialStage, StepType.REQUIREMENT_FIT, stepSortOrder++);
                        }
                        
                        if(job.getIncludeCulture())
                        {
                            createWorkFlowStep(objTran, initialStage, StepType.CULTURE_FIT, stepSortOrder++);
                        }
                        
                        createWorkFlowStep(objTran, initialStage, StepType.ROLE_FIT, stepSortOrder++);
                        
                        for(MessageTemplate mTemplate : messageTemplates)
                        {
                            createWorkFlowMessage(objTran, initialStage, mTemplate);
                        }
                        
                        for(WorkFlow workFlow : job.getWorkFlowsSet())
                        {
                            if(workFlow.getApplicationStatus() == ApplicationStatus.POST_INGEST || workFlow.getApplicationStatus() == ApplicationStatus.DRAFT || workFlow.getApplicationStatus() == ApplicationStatus.UNSUITABLE)
                            {
                                continue;
                            }
                            
                            createWorkFlowStage(objTran, wfTemplate, workFlow.getName(), getStageTypeByStatus(workFlow.getApplicationStatus()), sortOrder++);
                        }
                        
                        createWorkFlowStage(objTran, wfTemplate, "Successful", StageType.SUCCESSFUL, sortOrder++);
                        
                        createWorkFlowStage(objTran, wfTemplate, "Withdrew", StageType.WITHDREW, sortOrder++);
                        
                        createWorkFlowStage(objTran, wfTemplate, "Unsuitable", StageType.UNSUITABLE, sortOrder++);
                        
                        for(JobApplication jobApplication : job.getJobApplicationsSet())
                        {
                            jobApplication.setApplicantSource(jobApplication.isTrue(jobApplication.getIsEmailIngest()) ? ApplicantSource.INGEST : ApplicantSource.APPLY_URL);
                            jobApplication.setWorkFlowStage(getWFStageByStatus(wfTemplate, jobApplication.getApplicationStatus()));
                        }
                    }
                }
                catch (Exception e)
                {
                    throw new NestedException(e);
                }
            }
        });
    }

    private static void createWorkFlowMessage(ObjectTransaction objTran, WorkFlowStage stage, MessageTemplate mTemplate) throws StorageException, FieldException 
    {
        WorkFlowMessage         wfMessage   =   WorkFlowMessage.createWorkFlowMessage(objTran);
        Set<ApplicantSource>    sources     =   new HashSet();
        
        sources.add(mTemplate.getApplicationStatus() == ApplicationStatus.DRAFT ? ApplicantSource.APPLY_URL : ApplicantSource.INGEST);

        wfMessage.setWorkFlowStage(stage);
        wfMessage.setApplicantSources(sources);
        wfMessage.setBusinessHoursOnly(mTemplate.getBusinessHoursOnly());
        wfMessage.setMessageTemplate(mTemplate);
        wfMessage.setDelay(getDelay(mTemplate));
        wfMessage.setVariance(mTemplate.getVariance().toString() + "m");
    }

    private static WorkFlowStage createWorkFlowStage(ObjectTransaction objTran, WorkFlowTemplate wfTemplate, String name, StageType stageType, int sortOrder) throws FieldException, StorageException 
    {
        WorkFlowStage   wfStage =   WorkFlowStage.createWorkFlowStage(objTran);

        wfStage.setWorkFlowTemplate(wfTemplate);
        wfStage.setName(name);
        wfStage.setStageType(stageType);
        wfStage.setSortOrder(sortOrder);

        return wfStage;
    }
    
    private static WorkFlowStep createWorkFlowStep(ObjectTransaction objTran, WorkFlowStage wfStage, StepType stepType, int sortOrder) throws FieldException, StorageException 
    {
        WorkFlowStep    wfStep  =   WorkFlowStep.createWorkFlowStep(objTran);

        wfStep.setWorkFlowStage(wfStage);
        wfStep.setStepType(stepType);
        wfStep.setSortOrder(sortOrder);

        return wfStep;
    }
            
    private static String getDelay(MessageTemplate mTemplate) 
    {
        StringBuilder   sb  =   new StringBuilder();
        
        sb.append((int)(mTemplate.getDelayHrs()/24)).append("d:");
        sb.append(mTemplate.getDelayHrs()%24).append("h:");
        sb.append(mTemplate.getDelayMin()).append("m");
        
        return sb.toString();
    }
      
    public static StageType getStageTypeByStatus(ApplicationStatus status)
    {
        if(status == ApplicationStatus.POST_INGEST || status == ApplicationStatus.DRAFT)
        {
            return StageType.INITIAL;
        }
        else if(status == ApplicationStatus.UNSUITABLE)
        {
            return StageType.UNSUITABLE;
        }
        
        return StageType.GENERIC;
    }
    
    public static WorkFlowStage getWFStageByStatus(WorkFlowTemplate template , ApplicationStatus status)
    {
        if(status == ApplicationStatus.POST_INGEST || status == ApplicationStatus.DRAFT)
        {
            return getWFStage(template, StageType.INITIAL);
        }
        else if(status == ApplicationStatus.UNSUITABLE)
        {
            return getWFStage(template, StageType.UNSUITABLE);
        }
        
        return getWFStage(template, StageType.GENERIC);
    }

    private static WorkFlowStage getWFStage(WorkFlowTemplate template, StageType stageType) 
    {
        return template.pipelineWorkFlowTemplate().toWorkFlowStages(WorkFlowStage.SearchByAll().andStageType(new EqualsFilter<>(stageType))).val();
    }
}