package performa.form;

import com.stripe.Stripe;
import com.stripe.exception.APIConnectionException;
import com.stripe.exception.APIException;
import com.stripe.exception.AuthenticationException;
import com.stripe.exception.CardException;
import com.stripe.exception.InvalidRequestException;
import com.stripe.model.Customer;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import javax.servlet.http.HttpServletRequest;
import oneit.appservices.config.ConfigMgr;
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.servlets.security.SessionSecUserDecorator;
import oneit.utils.*;
import performa.intercom.utils.IntercomUtils;
import performa.orm.*;
import performa.orm.types.RoleType;
import performa.utils.StripeUtils;
import performa.utils.Utils;
import performa.utils.WebUtils;
 

public class SendCompanyUserInvitesFP extends SaveFP
{
    private static final LoggingArea    LOG                 =   LoggingArea.createLoggingArea("SendCompanyUserInvites");

    protected ConfigurableArticleTemplateEmailer  emailer;
    protected ConfigurableArticleTemplateEmailer  ownerAccountCreatedEmailer;
    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");
        CompanyUser         companyUser =   (CompanyUser) request.getAttribute("CompanyUser");
        Boolean             isSkip      =   CollectionUtils.equals((Boolean) request.getAttribute("Skip"), Boolean.TRUE);
        
        if(companyUser != null && companyUser == company.getAddedByUser())
        {
            if(!isSkip)
            {
                for(CompanyUser cUser : company.getUsersSet())
                {
                    if(!CollectionUtils.equals(cUser, company.getAddedByUser()))
                    {
                        SecUser secUser =   cUser.getUser();

                        BusinessObjectParser.assertFieldCondition(secUser.getEmail()!= null, secUser, SecUser.FIELD_Email, "mandatory", exceptions, true, request);

                        BusinessObjectParser.assertFieldCondition(!Utils.isCompanyUserEmailFound(process.getTransaction(), secUser.getEmail()), secUser, SecUser.FIELD_Email, "emailExists", exceptions, true, request);
                    }
                }
            }
        
            if(!company.isTrue(company.getIsVerified()))
            {
                BusinessObjectParser.assertFieldCondition(company.getCompanyName()!=null, company, Company.FIELD_CompanyName, "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");
        CompanyUser         companyUser     =   (CompanyUser) request.getAttribute("CompanyUser");
        SecUser             secUser         =   companyUser.getUser();
        Boolean             socialLogin     =   CollectionUtils.equals(process.getAttribute("socialLogin"), Boolean.TRUE);
        Boolean             isSkip          =   CollectionUtils.equals((Boolean) request.getAttribute("Skip"), Boolean.TRUE);

        LogMgr.log(LOG, LogLevel.PROCESSING1, "Verifing Company User", companyUser, secUser);

        companyUser.setIsAccountVerified(Boolean.TRUE);
        company.setIsVerified(Boolean.TRUE);

        sendAccountCreatedMail(companyUser, request);

        if(!socialLogin)
        {
            request.getSession().setAttribute (SecUser.SEC_USER_ID, secUser);
            request.getSession().setAttribute (SessionSecUserDecorator.REFRESH_SECURITY, Boolean.TRUE);
            
            LogMgr.log(LOG, LogLevel.PROCESSING1, "Password resetted", companyUser, secUser);
        }
        
        LogMgr.log(LOG, LogLevel.PROCESSING1, "Verifing Company User finished", companyUser, secUser);
        
        if(companyUser == company.getAddedByUser())
        {
            companyUser.setRole(RoleType.ADMIN);
            
            companyUser.setRoleTypes(RoleType.OWNER, RoleType.BILLING);
            
            // Create customer in Stripe and subscribe for plan 0001 and coupon EAP. Only for 0.0.4.1 release
            // Need to handle properly when plan and billing screens are added
            
            StripeUtils.createCustomer(companyUser);
            LogMgr.log(LOG, LogLevel.PROCESSING1,"Created customer in Stripe, customer reference ", company.getStripeReference());
            
//            StripeUtils.subscribeCustomer(company);
//            LogMgr.log(LOG, LogLevel.PROCESSING1,"Subscribed customer to default plan in Stripe, subscription reference ", company.getStripeSubscription());
            
            
            //process user invitations
            for(CompanyUser cUser : company.getUsersSet())
            {
                if(!CollectionUtils.equals(cUser, company.getAddedByUser()))
                {
                    SecUser sUser   =   cUser.getUser();

                    if(isSkip) //remove invitaions due to skip
                    {
                        sUser.removeFromExtensions(cUser);
                        cUser.delete();
                        sUser.delete();
                        
                        LogMgr.log(LOG, LogLevel.PROCESSING1, "Removed user details for skip.", cUser, sUser);
                    }
                    else
                    {
                        LogMgr.log(LOG, LogLevel.PROCESSING1, "Started to send invitaion email.", cUser);

                        sUser.setUserName(sUser.getEmail().toLowerCase());
                        sUser.setAttribute("md5:" + SecUser.FIELD_Password, CompanyUser.DEFAULT_PASSWORD);
                        sUser.addRole(Utils.getRole(Utils.ROLE_CLIENT, objTran));
                        cUser.setRole(RoleType.STANDARD);

                        LogMgr.log(LOG, LogLevel.PROCESSING1, "New user created :: ", sUser);

                        sendInvitationMail(cUser, request);

                        LogMgr.log(LOG, LogLevel.PROCESSING1, "End of sending invitation email.", cUser);
                    }
                }
            }
        }
        
        // Create company and the first user of it in intercom
        
        performa.intercom.resources.Company intercomCompany =   IntercomUtils.findOrCreateCompany(company);
        
        IntercomUtils.createIntercomUser(secUser, "Hiring Team", intercomCompany, companyUser.getPhone());
        
        return super.processForm(process, submission, params);
    }

    
    @Override
    public void init(ParticipantInitialisationContext context) throws InitialisationException
    {
        super.init(context);
        
        emailer                     =   (ConfigurableArticleTemplateEmailer) (context.getSingleChild("AccountCreatedEmailer"));
        ownerAccountCreatedEmailer  =   (ConfigurableArticleTemplateEmailer) (context.getSingleChild("OwnerAccountCreatedEmailer"));
        invitationEmailer           =   (ConfigurableArticleTemplateEmailer) (context.getSingleChild("InvitationEmailer"));
    }
    
    private void sendAccountCreatedMail(CompanyUser companyUser, HttpServletRequest request) throws BusinessException
    {
        try
        {
            LogMgr.log(LOG, LogLevel.PROCESSING1, "Sending Account Created mail from  SendCompanyUserInvitesFP to :: ", companyUser);

            String  link    =   LoopbackHTTP.getRemoteAccessURL(request) + "/extensions/adminportal/forgot_password.jsp";
            
            if(companyUser == companyUser.getCompany().getAddedByUser())
            {
                Article         article         =   WebUtils.getArticleByShortCut(companyUser.getTransaction(), WebUtils.JOBS);
                String          jobCreateLink   =   LoopbackHTTP.getRemoteAccessURL(request) 
                                                            + article.getLink(request, CollectionUtils.mapEntry("cms.rm", WebUtils.CREATE_JOB).toMap(), "/");
                Map             defaultParams   =   CollectionUtils.mapEntry("link", link)
                                                                    .mapEntry("create_job_link", jobCreateLink)
                                                                    .toMap(); 
                ObjectTransform transform       =   Utils.createCompoundTransform(defaultParams, companyUser.getUser(), companyUser.getCompany());

                Utils.sendMail(ownerAccountCreatedEmailer, transform, new String[]{companyUser.getEmailAddressFromUser()}, null, companyUser);
            }
            else
            {
                Map             defaultParams   =   CollectionUtils.mapEntry("link", link).toMap(); 
                ObjectTransform transform       =   Utils.createCompoundTransform(defaultParams, companyUser.getCompany(), companyUser.getUser());

                Utils.sendMail(emailer, transform, new String[]{companyUser.getEmailAddressFromUser()}, null, companyUser);
            }
            
            LogMgr.log(LOG, LogLevel.PROCESSING1, "Sent Account Created mail successfully from " + SendCompanyUserInvitesFP.class + " to :: ", companyUser);
        }
        catch (ConfigurableEmailerException ex)
        {
            LogMgr.log(LOG, LogLevel.SYSTEMERROR1, ex, "Error occured while sending mail for CompanyUser :: " + companyUser);

            throw new BusinessException("We are unable to send mail. Please try again or contact Talentology for more details.");
        }
    }
    
    private void sendInvitationMail(CompanyUser companyUser, HttpServletRequest request) throws BusinessException
    {
        if(!companyUser.isTrue(companyUser.getIsAccountVerified()))
        {
            try
            {
                LogMgr.log(LOG, LogLevel.PROCESSING1, "Sending invitation mail from  SendVerificationMailFP to :: ", companyUser);

                Article         invitationArticle   =   WebUtils.getArticleByShortCut(companyUser.getTransaction(), WebUtils.COMPANY_ACCOUNT_VERIFICATION);
                RandomStringGen random              =   new RandomStringGen();

                //set invitation key and send mail time
                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.getCompany().getAddedByUser().getUser());

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

                LogMgr.log(LOG, LogLevel.PROCESSING1, "Sent invitation mail successfully from " + SendVerificationMailFP.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 Talentology for more details.");
            }
        }
        else
        {
            LogMgr.log(LOG, LogLevel.PROCESSING1, "Call from " + SendVerificationMailFP.class + ". Account is already verified  for candidate :: ", companyUser);
        }
    }
}