package performa.orm;

import com.stripe.model.Card;
import com.stripe.model.Coupon;
import java.util.Date;
import java.util.Set;
import oneit.logging.LoggingArea;
import oneit.objstore.FieldWriteability;
import oneit.objstore.ValidationContext;
import oneit.objstore.rdbms.filters.EqualsFilter;
import oneit.security.SecUser;
import oneit.utils.BusinessException;
import oneit.utils.CollectionUtils;
import oneit.utils.DateDiff;
import oneit.utils.StringUtils;
import oneit.utils.filter.Filter;
import oneit.utils.math.NullArith;
import oneit.utils.parsers.FieldException;
import performa.orm.types.CurrencyType;
import performa.orm.types.RoleType;
import performa.utils.StripeUtils;


public class HiringTeam extends BaseHiringTeam
{
    private static final long serialVersionUID = 0L;
    
    public  static LoggingArea  LOG = LoggingArea.createLoggingArea("HiringTeam");

    // This constructor should not be called
    public HiringTeam ()
    {
        // Do not add any code to this, always put it in initialiseNewObject
    }
    
    public boolean showHasClientSupport()
    {
        return isTrue(getHasClientSupport());
    }
    
    @Override
    public String getToString() 
    {
        return StringUtils.subNulls(getHiringTeamName(), super.getToString());
    }
    
    public Set<CompanyUser> getActiveTeammates()
    {
        Filter<CompanyUser> filter  =   CompanyUser.SearchByAll()
                                                    .andIsAccountVerified(new EqualsFilter<>(Boolean.TRUE))
                                                    .andIsDisabled(new EqualsFilter<>(Boolean.FALSE));
        
        return CompanyUserHiringTeamLink.pipesCompanyUserHiringTeamLink(getUsersSet()).toCompanyUser(filter).uniqueVals();
    }
    
    public boolean isPPJ()
    {
        return isTrue(getIsPPJ());
    }
    
    public int getRemainingJobs()
    {
        return getPaymentPlan() != null && getPaymentPlan().getActiveJobCount() != null ? 
                    getPaymentPlan().getActiveJobCount() - getUsedCredits() : 0;
    }
    
    public Card getCard() throws FieldException
    {
       return StripeUtils.retrieveCard(this);
    }
    
    
    public String getCardNumber() throws FieldException
    {
        if(getStripeLast4() == null)
        {
            Card    card    =   StripeUtils.retrieveCard(this);
            
            if(card != null)
            {
                setStripeLast4(card.getLast4());
                setStripeBrand(card.getBrand());
                
                return "xxxx-xxxx-xxxx-" + getStripeLast4();
            }
            else
            {
                return "";
            }
        }
        
        return "xxxx-xxxx-xxxx-" + getStripeLast4();
    }
    
    
    public String getExpiry () throws FieldException
    {
        Card    card    =   StripeUtils.retrieveCard(this);

        return card != null ? String.format("%02d", card.getExpMonth()) + " / " + (card.getExpYear() % 100) : "";
    }

    
    @Override
    public Integer getMaxCap() 
    {
        return super.getMaxCap()!= null ? super.getMaxCap() : 0;
    }
    
    
    @Override
    public Integer getUsedCredits() 
    {
        return super.getUsedCredits() != null ? super.getUsedCredits() : 0;
    }

    
    @Override
    public Integer getPPJCredits() 
    {
        return super.getPPJCredits() != null ? super.getPPJCredits() : 0;
    }
    
    
    @Override
    public Integer getAvailableCredits() 
    {
        return super.getAvailableCredits()!= null ? super.getAvailableCredits() : 0;
    }
    
    
    @Override
    public Boolean getManageOwnBilling() 
    {
        return isTrue(super.getManageOwnBilling());
    }
    
    public boolean hasValidCoupon() throws FieldException
    {
        if(getCoupon() != null)
        {
            Coupon coupon   =   StripeUtils.retrieveCoupon(getCoupon().getCouponCode());

            if(coupon.getValid() && (getCouponExpiryDate() == null  || DateDiff.getToday().before(getCouponExpiryDate())))
            {
                return true;
            }
        }
        
        setCoupon(null);
        setCouponExpiryDate(null);
        
        return false;
    }
    
    
    public boolean hasValidCouponOn(Date date) throws FieldException
    {
        if(getCoupon() != null)
        {
            Coupon coupon   =   StripeUtils.retrieveCoupon(getCoupon().getCouponCode());

            if(coupon.getValid() && (getCouponExpiryDate() == null  || date.before(getCouponExpiryDate())))
            {
                return true;
            }
        }
        
        return false;
    }
    
    public boolean canCreateJob()
    {   
        if(getManageOwnBilling())
        {
            if(isTrue(getOnTrial()))
            {
                return getTrialJobCount() == 0;
            }
            
            return getPaymentPlan() != null && getStripeSubscription() != null && (getAvailableCredits()  > getUsedCredits() || !getHasCap() || (getHasCap() && getMaxCap() > getUsedCredits()));
        }
        
        return getBilledByTeam().canCreateJob();
    }

    
    @Override
    public FieldWriteability getObjectWriteability() 
    {
        SecUser secUser =   SecUser.getTXUser(getTransaction());
        
        if(secUser != null && secUser.getExtension(CompanyUser.REFERENCE_CompanyUser) != null)
        {
            CompanyUser companyUser =   secUser.getExtension(CompanyUser.REFERENCE_CompanyUser);
            
            if(companyUser != null && companyUser.getRoleForHiringTeam(this) == RoleType.STANDARD)
            {
                return FieldWriteability.NOT_IN_GUI;
            }
        }
        
        return super.getObjectWriteability();
    }

    
    @Override
    public FieldWriteability getWriteability_ManageOwnBilling() 
    {
        if(getManageOwnBilling() && getBillingTeamsCount() > 0)
        {
            return FieldWriteability.NOT_IN_GUI;
        }
        
        return super.getWriteability_ManageOwnBilling();
    }

    @Override
    public FieldWriteability getWriteability_BilledByTeam() 
    {
        if(!getManageOwnBilling())
        {
            return FieldWriteability.NOT_IN_GUI;
        }
        
        return super.getWriteability_ManageOwnBilling();
    }
    
    public Double getPPJAmount(Job job)
    {
//        double amount   =   job != null ? (job.getAssessmentType() == AssessmentType.COMPREHENSIVE ? PaymentPlan.PAY_PER_JOB_AMOUNT : PaymentPlan.PAY_PER_JOB_EXPRESS) : PaymentPlan.PAY_PER_JOB_AMOUNT;
        
        return getPPJAmount() * (getCoupon() != null ? (100 - getCoupon().getPercentageOff()) * 0.01 : 1);
    }
    
    public Double getPPJAmount()
    {
        CurrencyType    currency    =   getCountry().getCurrency();
        
        return  currency == CurrencyType.NZD ? 412D : 
                currency == CurrencyType.CAD ? 358D : 
                currency == CurrencyType.USD ? 277D : 
                currency == CurrencyType.GBP ? 212D : 
                currency == CurrencyType.EUR ? 239D : 385D;
    }
    
    
    public boolean createDefaultUser() throws FieldException
    {
        boolean addUser =   true;
        
        for (CompanyUserHiringTeamLink cUser : getUsersSet())
        {
            if(!CollectionUtils.equals(cUser.getCompanyUser(), getAddedByUser()))
            {
                addUser =   false;
            }
        }
        
        if(addUser)
        {
            SecUser                     secUser     =   SecUser.createSecUser(getTransaction());
            CompanyUser                 companyUser =   secUser.getExtensionOrCreate(CompanyUser.REFERENCE_CompanyUser);
            CompanyUserHiringTeamLink   link        =   CompanyUserHiringTeamLink.createCompanyUserHiringTeamLink(getTransaction());   
            
            link.setCompanyUser(companyUser);
            addToUsers(link);
        }
        
        return addUser;
    }
    
    public boolean isPlanActive(PaymentPlan paymentPlan)
    {
        return CollectionUtils.equals(getPaymentPlan(), paymentPlan);
    }

    public boolean hasBillingSetup()
    {
        if(getManageOwnBilling())
        {
            if(isTrue(getOnTrial()))
            {
                return true;
            }
            
            return getCardID() != null && getIsPPJ() != null && (getIsPPJ() || (!getIsPPJ() && getPaymentPlan() != null && getStripeSubscription() != null));
        }
        
        return getBilledByTeam().hasBillingSetup();
    }
    
    // if has plan, checking whether cap is reached
    public boolean allowJobCreation()
    {
        if(getManageOwnBilling())
        {
            if(isTrue(getOnTrial()))
            {
                return getTrialJobCount() == 0;
            }
            
            return isTrue(isPPJ()) || ( isFalse(isPPJ()) && getPaymentPlan() != null && getStripeSubscription() != null && (getAvailableCredits()  > getUsedCredits() || !getHasCap() || (getHasCap() && getMaxCap() > getUsedCredits())));
        }
        
        return getBilledByTeam().allowJobCreation();
    }
    
    public boolean trialJobNotAllowed()
    {
        return isTrue(getOnTrial()) && getTrialJobCount() == 1;
    }

    @Override
    public Integer getTrialJobCount() 
    {
        return super.getTrialJobCount() != null ? super.getTrialJobCount() : 0;
    }
    
    public void makePayment(Job job) throws BusinessException
    {
        if(getPPJCredits() > 0)
        {
            setPPJCredits(NullArith.subtract(getPPJCredits(), 1).intValue());
        }
        else
        {
            StripeUtils.makePayment(this, job);
        }
    }
}