package performa.intercom.utils;

import java.util.Arrays;
import java.util.Collection;
import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import oneit.logging.LogLevel;
import oneit.logging.LogMgr;
import oneit.logging.LoggingArea;
import oneit.objstore.StorageException;
import oneit.objstore.rdbms.filters.EqualsFilter;
import oneit.objstore.rdbms.filters.InFilter;
import oneit.objstore.utils.ObjstoreUtils;
import oneit.security.SecUser;
import oneit.utils.CollectionUtils;
import oneit.utils.ObjectTransform;
import oneit.utils.filter.CollectionFilter;
import oneit.utils.filter.Filter;
import performa.intercom.resources.AuthorizationException;
import performa.intercom.resources.ClientException;
import performa.intercom.resources.Company;
import performa.intercom.resources.CustomAttribute;
import performa.intercom.resources.Intercom;
import performa.intercom.resources.InvalidException;
import performa.intercom.resources.NotFoundException;
import performa.intercom.resources.RateLimitException;
import performa.intercom.resources.ServerException;
import performa.intercom.resources.User;
import performa.orm.Job;
import performa.orm.JobApplication;
import performa.orm.types.ApplicationStatus;
import performa.orm.types.JobStatus;
import performa.utils.Utils;


public class IntercomUtils 
{
    static
    {
        Intercom.setToken(Utils.INTERCOM_TOKEN);
        Intercom.setAppID(Utils.INTERCOM_APP_ID);
    }
    
    
    public static User createIntercomUser(SecUser secUser, String role, Company company, String phone)
    {
        try
        {
            User    user = new User();
                                
            user.setUserId(secUser.getIdentification());
            user.setEmail(secUser.getEmail());
            user.setName(secUser.getName());
            user.setPhone(phone);
            user.addCustomAttribute(CustomAttribute.newStringAttribute("role", role));    
            
            if(company != null)
            {
                user.addCompany(company);
            }
            
            User.create(user);
            
            LogMgr.log(LoggingArea.ALL, LogLevel.PROCESSING1, "Created Intercom User: ", user);

            return user;
        }
        catch (AuthorizationException | ClientException | ServerException | InvalidException | RateLimitException e)
        {
            LogMgr.log(LoggingArea.ALL, LogLevel.PROCESSING1, e, "Error while creating a user in intercom");
            
            return null;
        }
    }
    
    
    public static User findUserByID(SecUser secUser)
    {
        try
        { 
            Map<String, String> map = new HashMap<>();

            map.put("user_id", secUser.getIdentification());

            return User.find(map);
        }
        catch (AuthorizationException | ClientException | ServerException | InvalidException | RateLimitException | NotFoundException e)
        {
            LogMgr.log(LoggingArea.ALL, LogLevel.PROCESSING1, e, "Error while fetching a user by id from intercom");
            
            return null;
        }
    }
    
    
    public static User updateIntercomUser(SecUser secUser, String phone)
    {
        try
        {        
            User user   =   findUserByID(secUser);
            
            if(user != null)
            {
                user.setEmail(secUser.getEmail());
                user.setName(secUser.getName());
                user.setPhone(phone);
                User.update(user);
            }
            
            LogMgr.log(LoggingArea.ALL, LogLevel.PROCESSING1, "Updated Intercom User: ", user);

            return user;
        }
        catch (InvalidException | AuthorizationException e)
        {
            LogMgr.log(LoggingArea.ALL, LogLevel.PROCESSING1, e, "Error while updating a user in intercom");
            return null;
        }
    }
    
    
    public static Company createIntercomCompany(performa.orm.Company company)
    {
        try
        {        
            Company intercomCompany =   new Company();
                                                
            setCompanyDetails(intercomCompany, company);
            
            Company.create(intercomCompany);
            
            LogMgr.log(LoggingArea.ALL, LogLevel.PROCESSING1, "Created Intercom Company: ", intercomCompany);

            return intercomCompany;
        }
        catch (StorageException | InvalidException | AuthorizationException e)
        {
            LogMgr.log(LoggingArea.ALL, LogLevel.PROCESSING1, e, "Error while creating a company in intercom");
            
            return null;
        }
    }

    
    private static void setCompanyDetails(Company intercomCompany, performa.orm.Company company) throws StorageException 
    {
        intercomCompany.setName(company.getCompanyName());
        intercomCompany.setCompanyID(company.getID().toString());
        
        // job related custom attributes
        Job[]       jobs            =   Job.searchCompany(company.getTransaction(), company);
        Filter      draftFilter     =   Job.SearchByAll().andJobStatus(new EqualsFilter<>(JobStatus.DRAFT));
        Collection  draftJobs       =   CollectionFilter.filter(Arrays.asList(jobs), draftFilter);
        Filter      filledFilter    =   Job.SearchByAll().andJobStatus(new EqualsFilter<>(JobStatus.FILLED));
        Collection  filledJobs      =   CollectionFilter.filter(Arrays.asList(jobs), filledFilter);
        Filter      openFilter      =   Job.SearchByAll().andJobStatus(new EqualsFilter<>(JobStatus.OPEN));
        Collection  openJobs        =   CollectionFilter.filter(Arrays.asList(jobs), openFilter);
        Filter      closedFilter    =   Job.SearchByAll().andJobStatus(new EqualsFilter<>(JobStatus.COMPLETE));
        Collection  closedJobs      =   CollectionFilter.filter(Arrays.asList(jobs), closedFilter);
        Filter      manuallyFilter  =   Job.SearchByAll().andIsManuallyClosed(new EqualsFilter<>(Boolean.TRUE));
        Collection  manuallyClosed  =   CollectionFilter.filter(closedJobs, manuallyFilter);
        
        intercomCompany.addCustomAttribute(CustomAttribute.newIntegerAttribute("job-count",  jobs != null ? jobs.length : 0));
        intercomCompany.addCustomAttribute(CustomAttribute.newIntegerAttribute("draft-job-count",  draftJobs.size()));
        intercomCompany.addCustomAttribute(CustomAttribute.newIntegerAttribute("filled_job_count",  filledJobs.size()));
        intercomCompany.addCustomAttribute(CustomAttribute.newIntegerAttribute("open_job_count",  openJobs.size()));
        intercomCompany.addCustomAttribute(CustomAttribute.newIntegerAttribute("manually_closed_job_count",  manuallyClosed.size()));
        intercomCompany.addCustomAttribute(CustomAttribute.newIntegerAttribute("expired_job_count",  closedJobs.size() - manuallyClosed.size()));
        
        
        // applicant related custom attributes
        Filter      allApplicantFilter      =   JobApplication.SearchByAll().andApplicationStatus(new InFilter<>(ApplicationStatus.SUBMITTED, ApplicationStatus.SHORTLISTED, ApplicationStatus.UNSUITABLE));
        Collection  applicants              =   Job.pipesJob(jobs).toJobApplications(allApplicantFilter).uniqueVals();
        Filter      shortlistedFilter       =   JobApplication.SearchByAll().andApplicationStatus(new EqualsFilter<>(ApplicationStatus.SHORTLISTED));
        Collection  shortlistedApplicants   =   CollectionFilter.filter(applicants, shortlistedFilter);
        Filter      unsuitableFilter        =   JobApplication.SearchByAll().andApplicationStatus(new EqualsFilter<>(ApplicationStatus.UNSUITABLE));
        Collection  unsuitableApplicants    =   CollectionFilter.filter(applicants, unsuitableFilter);
        
        intercomCompany.addCustomAttribute(CustomAttribute.newIntegerAttribute("total_applicants",  applicants.size()));
        intercomCompany.addCustomAttribute(CustomAttribute.newIntegerAttribute("total_shortlisted",  shortlistedApplicants.size()));
        intercomCompany.addCustomAttribute(CustomAttribute.newIntegerAttribute("total_unsuitable",  unsuitableApplicants.size()));
        
                
        List<Job> sortedJobs    =   ObjstoreUtils.sort(Arrays.asList(jobs),
                                            new ObjectTransform[]{Job.pipesJob().toObjectCreated()},
                                            new Comparator[]{CollectionUtils.reverse(CollectionUtils.DEFAULT_COMPARATOR)});
        if(sortedJobs.size() > 0)
        {
            intercomCompany.addCustomAttribute(CustomAttribute.newLongAttribute("recent_job_created_at",  sortedJobs.get(0).getObjectCreated().getTime() / 1000));
        }
    }
    
    
    public static Company findCompanyByID(performa.orm.Company company)
    {
        try
        { 
            Map<String, String> map = new HashMap<>();

            map.put("company_id", company.getID().toString());

            return Company.find(map);
        }
        catch (InvalidException | AuthorizationException | NotFoundException e)
        {
            LogMgr.log(LoggingArea.ALL, LogLevel.PROCESSING1, e, "Error while fetching a company by id from intercom");
            
            return null;
        }
    }
    
    
    public static void updateCompany(performa.orm.Company company)
    {
        try
        { 
            Company intercomCompany =   findCompanyByID(company);
        
            if(intercomCompany == null)
            {
                createIntercomCompany(company);
            }
            else
            {
                setCompanyDetails(intercomCompany, company);
            
                Company.update(intercomCompany);
                
                LogMgr.log(LoggingArea.ALL, LogLevel.PROCESSING1, "Updated Intercom Company: ", intercomCompany);
            }
        }   
        catch (Exception e)
        {
            LogMgr.log(LoggingArea.ALL, LogLevel.PROCESSING1, e, "Error while updating company in intercom");
            
        }
    }
    
    
    public static Company findOrCreateCompany(performa.orm.Company company)
    {
        Company intercomCompany =   findCompanyByID(company);

        if(intercomCompany == null)
        {
            intercomCompany =   createIntercomCompany(company);
        }

        return intercomCompany;
    }
    
    
//    public static void createAccessedJobEvent(Job job, User user)
//    {
//        try
//        {
//            Map<String, CustomAttribute> customAttributes = user.getCustomAttributes();
//            customAttributes.get("shortlisted-count");
//            Event   event   =   new Event();
//
//            event.setEventName("accessed-job");
//            event.putMetadata("applicant-count", job.getNoOfCandidatesApplied());
//            event.putMetadata("shortlisted-count", job.getNoOfCandidatesShortlisted());
//            event.setUserID(user.getUserId());
//            event.setCreatedAt(currentTimeMillis()/1000L);
//
//            Event.create(event);
//        }   
//        catch (Exception e)
//        {
//            LogMgr.log(LoggingArea.ALL, LogLevel.PROCESSING1, e, "Error while creating accessed job event in intercom");
//            
//        }
//    }
}
