package performa.form;

import java.util.Date;
import java.util.Map;
import java.util.Set;
import javax.servlet.http.HttpServletRequest;
import oneit.business.content.Article;
import oneit.components.ParticipantInitialisationContext;
import oneit.email.ConfigurableArticleTemplateEmailer;
import oneit.email.ConfigurableEmailerException;
import oneit.logging.*;
import oneit.net.LoopbackHTTP;
import oneit.objstore.ObjectTransaction;
import oneit.objstore.StorageException;
import oneit.objstore.parser.BusinessObjectParser;
import oneit.security.SecUser;
import oneit.servlets.forms.*;
import oneit.servlets.process.*;
import oneit.utils.*;
import performa.orm.*;
import performa.utils.Utils;
import performa.utils.WebUtils;
 

public class SendUserInvitationFP extends SaveFP
{
    private static LoggingArea  LOG                 =   LoggingArea.createLoggingArea("SendUserInvitationFP");
    protected ConfigurableArticleTemplateEmailer invitationEmailer;
    
    @Override
    public void validate(ORMProcessState process, SubmissionDetails submission, MultiException exceptions, Map params) throws StorageException 
    {
        HttpServletRequest  request         =   submission.getRequest();
        Company             company         =   (Company) process.getAttribute("Company");
        InviteTeammateNPO   inviteTeammate  =   (InviteTeammateNPO) process.getAttribute("InviteTeammate");
        CompanyUser         resendUser      =   (CompanyUser) request.getAttribute("ResendUser");
        
        if(resendUser!=null)
        {
            BusinessObjectParser.assertFieldCondition(StringUtils.isEmailAddress(resendUser.getUser().getUserName()), resendUser, resendUser.FIELD_ObjectID, "invalidEmail", exceptions, false, request);
        }
        else
        {
            BusinessObjectParser.assertFieldCondition(inviteTeammate.getUserEmail() != null, inviteTeammate, InviteTeammateNPO.FIELD_UserEmail, "mandatory", exceptions, true, request);
            BusinessObjectParser.assertFieldCondition(StringUtils.isEmailAddress(inviteTeammate.getUserEmail()), inviteTeammate, InviteTeammateNPO.FIELD_UserEmail, "invalidEmail", exceptions, true, request);
//            BusinessObjectParser.assertFieldCondition(!Utils.userFoundInAnotherCompany(process.getTransaction(), inviteTeammate.getUserEmail() , company), inviteTeammate, InviteTeammateNPO.FIELD_UserEmail, "existsInOtherCompany", exceptions, true, request);
            BusinessObjectParser.assertFieldCondition(inviteTeammate.getRoleType() != null, inviteTeammate, InviteTeammateNPO.FIELD_RoleType, "mandatory", exceptions, true, request);
        }
        
        super.validate(process, submission, exceptions, params);
    }


    @Override
    public SuccessfulResult processForm(ORMProcessState process, SubmissionDetails submission, Map params) throws BusinessException, StorageException
    {
        HttpServletRequest  request         =   submission.getRequest();
        ObjectTransaction   objTran         =   process.getTransaction();
        Company             company         =   (Company) process.getAttribute("Company");
        InviteTeammateNPO   inviteTeammate  =   (InviteTeammateNPO) process.getAttribute("InviteTeammate");
        CompanyUser         resendUser      =   (CompanyUser) request.getAttribute("ResendUser");
        HiringTeam          hiringTeam      =   (HiringTeam) request.getAttribute("HiringTeam");
        
        if(resendUser!=null)
        {
            LogMgr.log(LOG, LogLevel.PROCESSING1, "Started to re-sending invitaion email.", resendUser);

            sendInvitationMail(resendUser, request, objTran);
            
            LogMgr.log(LOG, LogLevel.PROCESSING1, "End of re-sending invitation email.", resendUser);
        }
        else
        {
            LogMgr.log(LOG, LogLevel.PROCESSING1, "Started to create new use", company);

            SecUser secUser =   SecUser.searchNAME(objTran, inviteTeammate.getUserEmail().toLowerCase());
            
            if(secUser == null)
            {
                secUser =   SecUser.createSecUser(objTran);
                
                objTran.setAttrib(SecUser.CREATE_USER_KEY, true);
                
                secUser.setUserName(inviteTeammate.getUserEmail().toLowerCase());
            }
            
            CompanyUser comUser =   secUser.getExtension(CompanyUser.REFERENCE_CompanyUser);
            
            if(comUser == null)
            {
                //For Extension writeability
                objTran.setAttrib(SecUser.PASSWORD_WRITEABILITY_KEY, secUser.getID());
                
                comUser =   secUser.getExtensionOrCreate(CompanyUser.REFERENCE_CompanyUser);
                
                secUser.setEmail(secUser.getUserName());
                secUser.setAttribute("md5:" + SecUser.FIELD_Password, CompanyUser.DEFAULT_PASSWORD);
                secUser.addRole(Utils.getRole(Utils.ROLE_CLIENT, objTran));
                secUser.setFirstName(inviteTeammate.getFirstName());
                secUser.setLastName(inviteTeammate.getLastName());
            
                comUser.setDefaultHiringTeam(hiringTeam);
                comUser.setCompany(company);
            }
            
            Set<HiringTeam> existingTeams   =   comUser.pipelineCompanyUser().toHiringTeams().toHiringTeam().uniqueVals();
            
            if(!existingTeams.contains(hiringTeam))
            {
                // setting the default hiring team selected above the screen
                CompanyUserHiringTeamLink link  =   CompanyUserHiringTeamLink.createCompanyUserHiringTeamLink(objTran);

                link.setCompanyUser(comUser);
                link.setHiringTeam(hiringTeam);
                link.setRole(inviteTeammate.getRoleType());
                
                existingTeams.add(hiringTeam);
            }
            
            // setting additional hiring teams added when inviting
            for (HiringTeamLinkNPO teamLinkNPO : inviteTeammate.getHiringTeamsSet())
            {
                // avoid adding link to same team twice
                if(!existingTeams.contains(teamLinkNPO.getHiringTeam()) && teamLinkNPO.getHiringTeam() != null)
                {
                    CompanyUserHiringTeamLink teamLink  =   CompanyUserHiringTeamLink.createCompanyUserHiringTeamLink(objTran);

                    teamLink.setCompanyUser(comUser);
                    teamLink.setHiringTeam(teamLinkNPO.getHiringTeam());
                    teamLink.setRole(inviteTeammate.getRoleType());
                
                    existingTeams.add(teamLinkNPO.getHiringTeam());
                }
            }
            
            LogMgr.log(LOG, LogLevel.PROCESSING1, "New user created :: ", secUser);

            sendInvitationMail(comUser, request, objTran);
            
            LogMgr.log(LOG, LogLevel.PROCESSING1, "End of sending invitation email.", secUser);
        }

        return super.processForm(process, submission, params);
    }

    
    @Override
    public void init(ParticipantInitialisationContext context) throws InitialisationException
    {
        super.init(context);
        
        invitationEmailer   =   (ConfigurableArticleTemplateEmailer) (context.getSingleChild("InvitationEmailer"));
    }
    
    
    protected void sendInvitationMail(CompanyUser companyUser, HttpServletRequest request, ObjectTransaction objTran) throws BusinessException
    {
        if(!companyUser.isTrue(companyUser.getIsAccountVerified()))
        {
            try
            {
                LogMgr.log(LOG, LogLevel.PROCESSING1, "Sending invitation mail from  SendUserInvitationFP to :: ", companyUser);

                Article invitationArticle   =   WebUtils.getArticleByShortCut(companyUser.getTransaction(), WebUtils.COMPANY_ACCOUNT_VERIFICATION);
               
                //set invitation key and send mail time
                if(companyUser.getVerificationKey()==null)
                {
                    RandomStringGen random  =   new RandomStringGen();

                    companyUser.setVerificationKey(random.generateAlphaNum(6));
                }

                companyUser.setVerificationMailSendDate(new Date());

                String          link            =   LoopbackHTTP.getRemoteAccessURL(request) 
                                                        + invitationArticle.getLink(request, CollectionUtils.EMPTY_MAP, "/") 
                                                        + "?id=" + companyUser.getID()
                                                        + "&key=" + companyUser.getVerificationKey();
                Map             defaultParams   =   CollectionUtils.mapEntry("link", link).toMap(); 
                ObjectTransform transform       =   Utils.createCompoundTransform(defaultParams, companyUser.getCompany(),companyUser.getDefaultHiringTeam(), SecUser.getTXUser(objTran));

                Utils.sendMail(invitationEmailer, transform, new String[]{companyUser.getEmailAddressFromUser()}, null, companyUser);

                LogMgr.log(LOG, LogLevel.PROCESSING1, "Sent invitation mail successfully from " + SendUserInvitationFP.class + " to :: ", companyUser);
            }
            catch (ConfigurableEmailerException ex)
            {
                LogMgr.log(LOG, LogLevel.SYSTEMERROR1, ex, "Error occured while sending mail for Candidate :: " + companyUser);

                throw new BusinessException("We are unable to send mail. Please try again or contact Matchd for more details.");
            }
        }
        else
        {
            LogMgr.log(LOG, LogLevel.PROCESSING1, "Call from " + SendUserInvitationFP.class + ". Account is already verified  for candidate :: ", companyUser);
        }
    }
}