<?php

namespace Hilco\Models;

use Exception;
use Hilco\GuzzleWrappers\RequestBuilders\TaxRequestBuilder;
use HilcoB2B\Notifications\HilcoResetPasswordNotification;
use HilcoAPI\Helpers\HubSpotHelper;
use Illuminate\Auth\Authenticatable;
use Illuminate\Auth\Passwords\CanResetPassword;
use Illuminate\Contracts\Auth\Access\Authorizable as AuthorizableContract;
use Illuminate\Contracts\Auth\Authenticatable as AuthenticatableContract;
use Illuminate\Contracts\Auth\CanResetPassword as CanResetPasswordContract;
use Illuminate\Database\Eloquent\Collection;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Illuminate\Database\Eloquent\Relations\BelongsToMany;
use Illuminate\Database\Eloquent\Relations\HasMany;
use Illuminate\Database\Eloquent\Relations\HasOne;
use Illuminate\Database\Query\Builder;
use Illuminate\Foundation\Auth\Access\Authorizable;
use Illuminate\Notifications\Notifiable;
use Klaviyo\ApiException;
use KlaviyoAPI\KlaviyoAPI;
use KlaviyoAPI\Model\EventCreateQueryV2;
use KlaviyoAPI\Model\ProfileCreateQuery;
use KlaviyoAPI\Model\ProfilePartialUpdateQuery;
use KlaviyoAPI\Model\SubscriptionCreateJobCreateQuery;
use Illuminate\Support\Arr;
use Log;
use URL;

/**
 * Hilco\Models\WebUser
 *
 * @property integer $id
 * @property string $email
 * @property string $password
 * @property string $name
 * @property integer $customer_id
 * @property string $remember_token
 * @property string $last_login
 * @property string $date_created
 * @property string $date_modified
 * @property string $deleted_at
 * @property bool $needs_password_reset
 * @property string $username
 * @property integer $parent_webuser_id
 * @property string $date_uploaded
 * @property string $klaviyo_profile_id
 * @property string $hubspot_contact_id
 * @method static Builder|WebUser whereId($value)
 * @method static Builder|WebUser whereEmail($value)
 * @method static Builder|WebUser wherePassword($value)
 * @method static Builder|WebUser whereName($value)
 * @method static Builder|WebUser whereCustomerId($value)
 * @method static Builder|WebUser whereRememberToken($value)
 * @method static Builder|WebUser whereDateCreated($value)
 * @method static Builder|WebUser whereDateModified($value)
 * @method static Builder|WebUser whereDateUploaded($value)
 * @method static Builder|WebUser whereDeletedAt($value)
 * @method static Builder|WebUser whereLastLogin($value)
 * @method static WebUser firstOrNew($attributes)
 * @mixin \Eloquent
 * @property-read Customer $customer
 * @property-read WebAuthEvent[]|Collection $webAuthEvents
 * @property-read WebRole[]|Collection $webRoles
 * @property-read WebPermission[]|Collection $webPermissions
 * @property-read WebUserPersona[]|Collection $webUserPersonas
 * @property-read WebSilo_WebUser $webSiloWebUser
 * @property-read WebUser $parentWebUser
 * @property-read WebFeedbackResponse[]|Collection $webFeedbackResponses
 * @property-read Order[]|Collection $webOrders
 * @property-read Order $latestWebOrder
 * @method static withHubSpotContact()
 * @method static withoutHubSpotContact()
 */
class WebUser extends WebModel implements AuthenticatableContract, AuthorizableContract, CanResetPasswordContract {
	use Authenticatable, Authorizable, CanResetPassword, Notifiable;

	protected $table = "WebUsers";
	protected $fillable = ['email', 'password', 'username', 'name', 'customer_id', 'is_enabled', 'needs_password_reset', 'default_websilo_id', 'parent_webuser_id', 'klaviyo_profile_id', 'webRoles', 'webRoleIds', 'webUserPersonas', 'webUserPersonaIds', 'webPermissions', 'webPermissionIds', 'commit_sequence', 'hubspot_contact_id'];
	protected $hidden = ['password', 'remember_token'];
    protected $with = ['customer.segments'];

    const HIDDEN = 'HIDDEN';

    public function scopeUsername($query, $username) {
        return $query->where('username', $username);
    }

	public function customer(): BelongsTo {
		return $this->belongsTo(Customer::class, 'customer_id', 'id');
	}

	public function payment_profile()
	{
		return $this->hasOne(UserPaymentProfile::class, 'user_id', 'id');
	}

    public function webAuthEvents(): HasMany {
	    return $this->hasMany(WebAuthEvent::class, 'email', 'email');
    }

	public function webRoles(): BelongsToMany {
        return $this->belongsToMany(WebRole::class, 'WebRole_WebUser', 'webuser_id', 'webrole_id');
    }

    public function webPermissions(): BelongsToMany {
        return $this->belongsToMany(WebPermission::class, 'WebPermission_WebUser', 'webuser_id', 'webpermission_id');
    }

    /**
     * @return mixed
     */
    public function divisionPermissions() {
        $uniqueM3DivisionCodes =
            CustomerSegment::whereRaw('m3_division_code IS NOT NULL AND m3_division_code != ""')
                ->distinct('m3_division_code')
                ->pluck('m3_division_code')
                ->toArray();

        return $this->effective_permissions->filter(function ($perm) use ($uniqueM3DivisionCodes) {
            return in_array($perm->slug, $uniqueM3DivisionCodes);
        });
    }

    /**
     * @return BelongsToMany
     */
    public function webSilo() {
        return $this
            ->belongsToMany(WebSilo::class, 'WebSilo_WebUser', 'webuser_id', 'websilo_id')
            ->withPivot(['spending_limit', 'spending_period', 'minimum_order'])
            ;
    }

    /**
     * @return BelongsToMany
     */
    public function webUserPersonas(): BelongsToMany {
        return $this
            ->belongsToMany(WebUserPersona::class, 'WebUser_WebUserPersona', 'webuser_id', 'webuserpersona_id');
    }

    public function webSilos() {
        return $this
            ->belongsToMany(WebSilo::class, 'WebSilo_WebUser', 'webuser_id', 'websilo_id')
            ->withPivot(['spending_limit', 'spending_period', 'minimum_order'])
            ;
    }

    /**
     * @return HasOne
     */
    public function webSiloWebUser(): HasOne {
        return $this->hasOne(WebSilo_WebUser::class, 'webuser_id', 'id');
    }

    public function getWebSiloAttribute() {
        $webSilo = $this->getRelationValue('webSilo')->first();
        if ($webSilo) return $webSilo;
        return WebSilo::default();
    }

    /**
     * @deprecated this is never set correctly, also webuser should only be implicitly assigned to a microsite via customer relation
     */
    public function defaultWebSilo() {
        return $this->belongsTo(WebSilo::class, 'default_websilo_id', 'id');
    }

    public function parentWebUser(): BelongsTo {
        return $this->belongsTo(WebUser::class, 'parent_webuser_id', 'id');
    }

    public function favoriteFamilies() {
        return $this
            ->belongsToMany(WebFamily::class, WebFamily_WebUser::class, 'webuser_id', 'webfamily_id')
            ->where('WebFamily_WebUser.deleted_at', '=', '0000-00-00 00:00:00')
            ->webVisible()
            ->with('visibleWebParts')
        ;
    }

    /**
     * because favoriteFamilies() has all those with's.....
     * @return BelongsToMany
     */
    public function favoriteFamiliesOnly(): BelongsToMany {
        return $this->belongsToMany(WebFamily::class, WebFamily_WebUser::class, 'webuser_id', 'webfamily_id')
            ->wherePivot('WebFamily_WebUser.deleted_at', '=', '0000-00-00 00:00:00');
    }

	public function can($permissionSlug, $arguments = []) {
        return $this->checkPermission($permissionSlug);
    }

    public function hasRole($roleSlug) {
        return $this->webRoles->where('slug', $roleSlug)->count() > 0;
    }

    public function hasDirectPermission($permissions) {
        if ($permissions instanceof WebPermission) $permissions = $permissions->slug;
        if (!is_array($permissions)) $permissions = [$permissions];
        return $this->webPermissions->whereIn('slug', $permissions)->count() > 0;
    }

    public function hasRolePermission($permissions) {
        if ($permissions instanceof WebPermission) $permissions = $permissions->slug;
        if (!is_array($permissions)) $permissions = [$permissions];
        return $this->webRoles->pluck('webPermissions')->flatten()->whereIn('slug', $permissions)->count() > 0;
    }

	protected function checkPermission($permissionSlug) {
        return $this->effective_permissions->where('slug', $permissionSlug)->count() > 0;
    }

	public function getEffectivePermissionsAttribute() {
	    $rolePemissions = $this->webRoles->pluck('webPermissions')->flatten()->keyBy('id');
        $userPermissions = $this->webPermissions->keyBy('id');
        return $rolePemissions->merge($userPermissions);
	}

	public function userPhone() {
		$this->hasOne(CustomerPhone::class, 'customer_id', 'customer_id');
	}

    public function hasActiveCustomer() {
        return !is_null($this->active_customer);
    }

    public function setWebRolesAttribute($webRoleIds) {
        $this->webRoles()->sync($webRoleIds);
    }

    public function setWebRoleIdsAttribute($ids) {
        return $this->setWebRolesAttribute($ids);
    }

    public function getWebRoleIdsAttribute() {
        return $this->webRoles->pluck('id')->toArray();
    }

    public function setWebUserPersonasAttribute($webUserPersonaIds) {
        $this->webUserPersonas()->sync($webUserPersonaIds);
    }

    public function setWebUserPersonaIdsAttribute($ids) {
        return $this->setWebUserPersonasAttribute($ids);
    }

    public function getWebUserPersonaIdsAttribute() {
        return $this->webUserPersonas->pluck('id')->toArray();
    }

    public function setWebPermissionIdsAttribute($ids) {
        $this->webPermissions()->sync($ids);
    }

    public function webFeedbackResponses(): HasMany {
	    return $this->hasMany(WebFeedbackResponse::class, 'webuser_id', 'id');
    }

    // TODO: Probably consider migrating this somewhere other than the WebUser.

    /**
     * @param CustomerShippingAddress $shippingAddress
     * @return array|int
     */
    public function getTaxes($shippingAddress) {
        $taxes = [];
        $customer = b2b()->activeCustomer();
        if (is_null($customer)) return 0;

        $segment = $customer->activeSegment;
        if (is_null($segment)) return 0;

        $taxRequestBuilder = new TaxRequestBuilder([
            'shippingAddress1' => $shippingAddress->addr_1,
            'shippingAddress2' => $shippingAddress->addr_2,
            'shippingAddress3' => $shippingAddress->addr_3,
            'shippingAddress4' => $shippingAddress->addr_4,
            'shippingAddress5' => $shippingAddress->addr_5,
            'city' => $shippingAddress->city,
            'mainDivision' => $shippingAddress->state,
            'postalCode' => $shippingAddress->postal_cd,
            'country' => $shippingAddress->country,
            'customer_code' => $segment->cust_no
        ]);

        $taxRequest = $taxRequestBuilder->requestTaxes();

        $tax = 0;
        if($taxRequest) {
            $tax = $taxRequest * 100;
        }
//        $additionalTaxCustomerSegments = $segment->additionalTaxCustomerSegment;
//        if ($additionalTaxCustomerSegments) {
//            foreach ($additionalTaxCustomerSegments as $additionalTaxCustomerSegment) {
//                $additionalTaxes = $additionalTaxCustomerSegment->additionalTax;
//                if ($additionalTaxes) {
//                    foreach ($additionalTaxes as $additionalTax) {
//                        $taxes[] = $additionalTax->tax_percentage;
//                    }
//                }
//            }
//        }
//
//        $tax = StateTax::inEffect()->whereState($shippingAddress->state)->first();
//        if ($tax) {
//            $taxes[] = $tax->tax_percentage;
//        }
//
//        return $taxes;
        return $tax;
    }

    public function getHasActiveCustomerSegmentAttribute() {
	    $customer = $this->customer;
	    if (is_null($customer)) return false;

	    return !is_null($customer->activeSegment);
    }

    /**
     * I don't think this is used anywhere since I changed the only call I found for it to be
     *   Arr::get($this->customer, 'customerSegment.primarySalesRep.pointman_name')
     * but I'm not positive so I didn't remove it -- chris
     */
    public function getPrimarySalesRep() {
        $activeCustomerSegment = $this->customer->customerSegment;

        if ($activeCustomerSegment != null && $activeCustomerSegment->primarySalesRep != null) {
            return $activeCustomerSegment->primarySalesRep->pointman_name;
        } else {
            return '';
        }
    }

    public function getLastSalesCallDate() {
        $activeCustomerSegment = $this->customer->getActiveSegmentAttribute();
        if ($activeCustomerSegment != null) {
            $latestCall = $activeCustomerSegment->getLatestCallAmongAffiliates();
            if ($latestCall != null) {
                $date = $latestCall->start_time;
                return date('Y-m-d', strtotime($date));
            }
        }

        return '';
    }

    public function getLicenseExpiration() {
        $defaultShippingAddress = $this->customer->default_shipping_address;
        if ($defaultShippingAddress != null) {
            $defaultLicense = $this->customer->customerPharmacyLicenses()->where('shipto_address_no', $defaultShippingAddress->addr_no)->first();
            if (isset($defaultLicense) && isset($defaultLicense->customerPharmacyInfo) && $defaultLicense->customerPharmacyInfo->license_expiration_date != '0000-00-00') {
                return $defaultLicense->customerPharmacyInfo->license_expiration_date;
            }
        }
        return '';
    }

    public function getRegion() {
        return $this->customer->country;
    }

    public function getBuyingGroupName() {
        $activeCustomerSegment = $this->customer->getActiveSegmentAttribute();

        if ($activeCustomerSegment != null) {
            return $activeCustomerSegment->bill_cust_name;
        }

        return '';
    }

    public function getMicrositeNameAttribute() {
        $micrositeName = false;

        $customerWebSilo = $this->customer->webSilo;
        if ($customerWebSilo && $customerWebSilo->is_visible) {
            $micrositeName = $customerWebSilo->name;
        }

        return $micrositeName === false ? '' : $micrositeName;
    }

    public function get4PDesignation() {
        $customer = $this->customer;
        $customer4P = $customer->customer4P;

        if ($customer4P != null) {
            return $customer4P->fourp;
        }

        return '';
    }

    /**
     * @deprecated Hilco Rewards Program no longer uses a tiers system
     */
    public function getRewardsTier() {
        return rewards()->tierName();
    }

    /**
     * @deprecated Hilco Rewards Program no longer tracks total spending
     */
    public function getTotalSpend() {
        return rewards()->totalSpending();

    }

    /**
     * @deprecated Hilco Rewards Program no longer tracks spending by productcategorygroup
     */
    public function getCategoryGroupSpendingArray() {
        return rewards()->productCategoryGroups($this->customer);
    }

    /**
     * @deprecated Hilco Rewards Program no longer has tier spending requirements
     */
    public function getSpendNeeded() {
        return rewards()->calculateSpendingToUpgrade();
    }

    /**
     * @deprecated Hilco Rewards Program no longer has category-spend requirements
     */
    public function getCategoriesNeeded() {
        return rewards()->calculateCategoriesToUpgrade();
    }

    public function getCustomerCategory() {
        $customer = $this->customer;
        $customerCategory = $customer->overrideCustomerCategory ? $customer->overrideCustomerCategory : $customer->customerCategory;

        if ($customerCategory != null)
            return $customerCategory->cust_category;
        else {
            return '';
        }
    }

    public function getLanguageCodeAttribute() {

        if ($this->customer->customerLastLanguageUsed != null) {
            return $this->customer->customerLastLanguageUsed->language_code;
        }

        $language_code = false;

        $customerWebSilo = $this->customer->webSilo;
        if ($customerWebSilo && $customerWebSilo->is_visible && !is_null($customerWebSilo->defaultLanguage())) {
            $language_code = $customerWebSilo->defaultLanguage()->language_code;
        }

        return $language_code === false ? '' : $language_code;
    }

    public function getKlaviyoProfileArrayAttribute(): array {
        $rewardsPromotion = Promotion::find(config('hilco.rewardsPromotionId'));

        $klaviyoListId = "";
        $rewardsEligible = false; // rewards eligibility is meeting all rewards promo trigger requirements except list-enrollment and cart $
        if (isset($rewardsPromotion)) {
            foreach ($rewardsPromotion->triggers as $trigger) {
                if ($trigger->trigger_type == 'klaviyoListTrigger') {
                    $klaviyoListId = $trigger->details->klaviyo_list;
                } else if (!in_array($trigger->trigger_type, ['currentOrderTrigger', 'sourceTrigger', 'itemQuantityTrigger'])) {
                    $rewardsEligible = $trigger->details->isTriggered($this->customer, null, null);
                    if (!$rewardsEligible) break;
                }
            }
        }
        $isLegacyRewards = isset($this->customer->legacyRewardsCustomer); // being a legacy customer overrides needing a list-enrollment
        $userRewardsEnrolled = $isLegacyRewards || $this->isRewardsEnrolled($klaviyoListId);
        $accountRewardsEnrolled = $userRewardsEnrolled ?: $this->customer->isRewardsEnrolled($klaviyoListId);

        $lastWebOrderDate = null;
        $latestWebOrder = $this->latestWebOrder;
        if (isset($latestWebOrder)) {
            $lastWebOrderDate = $latestWebOrder->order_date;
        }

        $array = [
            'id' => $this->id,
            '$email' => trim($this->email),
            'accountNumber' => $this->customer->cust_no,
            'name' => $this->name,
            'salesRep' => Arr::get($this->customer, 'customerSegment.primarySalesRep.pointman_name', ''),
            'secondaryRep' => Arr::get($this->customer, 'customerSegment.secondarySalesRep.pointman_name', ''),
            'lifecycleStage' => Arr::get($this, 'customer.affiliateCustomer.currentCustomerLifecycle.lifecycle.name', ''),
            'lastSalesCallDate' => $this->getLastSalesCallDate(),
            'licenseExpiration' => $this->getLicenseExpiration(),
            'region' => $this->getRegion(),
            'buyingGroup' => $this->getBuyingGroupName(),
            'microsite' => $this->micrositeName,
            'priceListDesignation' => $this->customer->defaultPriceList,
            'account-rewards-enrolled' => $accountRewardsEnrolled ? 'Yes' : 'No',
            'user-rewards-enrolled' => $userRewardsEnrolled ? 'Yes' : 'No',
            'rewardsEligible' => $rewardsEligible ? 'Yes' : 'No',
            'totalSpend6Months' => $this->customer->totalSpending6m(),
            'totalSpend12Months' => $this->customer->totalSpending12m(),
            'totalSpend18Months' => $this->customer->totalSpending18m(),
            'customerCategory' => $this->getCustomerCategory(),
            'lastWebOrderDate' => $lastWebOrderDate,
            'currency' => $this->customer->currency,
            'language' => $this->languageCode,
            'lastOrderDate' => $this->customer->recentOrders(1)->max('order_date'),
            'rewardsLegacy' => $isLegacyRewards ? 'Yes' : 'No',
        ];

        foreach ($this->customer->getSpendingArray() as $groupDesc => $productCategorySpendingArr) {
            $array['6month-spending-' . $groupDesc] = $productCategorySpendingArr['6month']->spending;
            $array['12month-spending-' . $groupDesc] = $productCategorySpendingArr['12month']->spending;
            $array['18month-spending-' . $groupDesc] = $productCategorySpendingArr['18month']->spending;
        }
        return $array;
    }

    public function calculateHubSpotContactProperties(): array {
        $YES = 'Yes'; $NO = 'No';
        $hubspotSubId = null;
        $rewardsPromotion = Promotion::find(config('hilco.rewardsPromotionId'));
        $rewardsEligible = false; // rewards eligibility is meeting all rewards promo trigger requirements except list-enrollment and cart $
        if (isset($rewardsPromotion)) {
            foreach ($rewardsPromotion->triggers as $trigger) {
                if ($trigger->trigger_type == 'hubspotSubTrigger') {
                    $hubspotSubId = $trigger->details->subscriptionid;
                } else if (!in_array($trigger->trigger_type, ['currentOrderTrigger', 'sourceTrigger', 'itemQuantityTrigger'])) {
                    $rewardsEligible = $trigger->details->isTriggered($this->customer, null, null);
                    if (!$rewardsEligible) break;
                }
            }
        }
        $userRewardsEnrolled = $this->isRewardsEnrolled($hubspotSubId);
        $accountRewardsEnrolled = $userRewardsEnrolled ?: $this->customer->isRewardsEnrolled($hubspotSubId);
        $lastWebOrderDate = null;
        $latestWebOrder = $this->latestWebOrder;
        if (isset($latestWebOrder)) {
            $lastWebOrderDate = $latestWebOrder->order_date;
        }
        $props = [
            'account_rewards_enrolled'      => $accountRewardsEnrolled ? $YES : $NO,
            'billtoacct_'                   => $this->customer->customerSegment->billToCustomer->cust_no,
            'currency'                      => $this->customer->currency,
            'customer_category'             => $this->getCustomerCategory(),
            'customer_parent_number'        => $this->customer->customerSegment->parentCustomer->cust_no,
            'directbill'                    => $this->customer->customerSegment->billsDirect ? $YES : $NO,
            'email'                         => $this->email,
            'hs_country_region'             => $this->getRegion(),
            'lastorderdate'                 => $this->customer->recentOrders(1)->max('order_date'),
            'lastsalescalldate'             => $this->getLastSalesCallDate(),
            'lastweborderdate'              => $lastWebOrderDate,
            'license_expiration_date'       => $this->getLicenseExpiration(),
            'microsite'                     => $this->micrositeName,
            'pricelistdesignation'          => $this->customer->defaultPriceList,
            'rewardseligible'               => $rewardsEligible ? $YES : $NO,
            'totalspend6months'             => $this->customer->totalSpending6m(),
            'totalspend12months'            => $this->customer->totalSpending12m(),
            'totalspend18months'            => $this->customer->totalSpending18m(),
            'user_rewards_enrolled'         => $userRewardsEnrolled ? $YES : $NO,
        ];
        $preferredLanguage = $this->languageCode;
        if (!empty($preferredLanguage)) {
            $props['hs_language'] = substr($preferredLanguage, 0, 2);
        }
        if (!config('hubspot.is_sandbox', false)) {
            $props['accountnumber'] = $this->customer->cust_no;
        }
        return $props;
    }

    public function getHubSpotContactId() {
        return $this->hubspot_contact_id;
    }

    /**
     * NOTE: this deliberately skips evaluating cart or platform triggers
     * @param $promotion
     * @return bool
     */
    public function isPromoEligible($promotion): bool {
        if (is_null($promotion)) return false;
        $triggered = true;
        foreach ($promotion->triggers as $trigger){
            if(!in_array($trigger->trigger_type, ['currentOrderTrigger', 'sourceTrigger', 'itemQuantityTrigger'])){
                $triggered = $trigger->details->isTriggered($this->customer, null, null);
            }
        }

        return $triggered;
    }

    /**
     * NOTE: this deliberately skips evaluating the Klaviyo List Trigger on the Rewards promotion
     * @param $rewardsPromotion
     * @param $pricelistConnection
     * @return bool
     */
    public function isRewardsQualifying ($rewardsPromotion, $pricelistConnection = null): bool {
        return $this->customer->isRewardsQualifying($rewardsPromotion, $this, $pricelistConnection);
    }

    /**
     * @param $klaviyoListId
     * @return bool
     */
    public function isRewardsEnrolled ($klaviyoListId): bool {
        if (isset($this->customer->legacyRewardsCustomer)) {
            return true;
        }
//        if (empty($hubspotSubId)) {
//            $rewardsPromotion = Promotion::find(config('hilco.rewardsPromotionId'));
//            if (isset($rewardsPromotion)) {
//                foreach ($rewardsPromotion->triggers as $trigger) {
//                    if ($trigger->trigger_type == 'hubspotSubTrigger') {
//                        $hubspotSubId = $trigger->details->subscriptionid;
//                        break;
//                    }
//                }
//                if (empty($hubspotSubId)) {
//                    return false;
//                }
//            }
//        }
        return $this->isHubSpotMarketingContact();
    }

    /**
     * @param $hubspotSubId
     * @return bool
     */
    public function isSubscribedToHubspotSub ($hubspotSubId) {
        if (empty($hubspotSubId)) return false;

        foreach (HubSpotHelper::lookupContactSubscriptions($this) as $publicSubscriptionStatus) {
            if ($publicSubscriptionStatus->getId() == $hubspotSubId) {
                if ($publicSubscriptionStatus->getStatus() == PublicSubscriptionStatus::STATUS_SUBSCRIBED) {
                    return true;
                }
            }
        }

        return false;
    }

    public function isHubSpotMarketingContact() {
        $contact = HubSpotHelper::lookupContact($this);
        if (is_null($contact)) {
            return false;
        } else {
            $props = $contact->getProperties();
            return Arr::get($props, "marketing_contact", "No") == "yes";
        }
    }

    /**
     * @param $klaviyo_list
     * @return bool
     */
    public function isSubscribedToKlaviyoList ($klaviyo_list): bool {
        if (empty($klaviyo_list)) return false;
//        $cachedListSub = KlaviyoListSubscriptionResult::byKlaviyoListAndCustomer($klaviyo_list, $this->customer->id)->first();
//        if (isset($cachedListSub) && !$cachedListSub->isExpired()) {
//            return $cachedListSub->isSubscribed();
//        }
        $webSilo = $this->customer->webSilo;
        $klaviyoClient = new KlaviyoAPI($webSilo->klaviyo_api_key);

        $email = trim($this->email);
        $membershipsArray = [];

        if(filter_var($email, FILTER_VALIDATE_EMAIL)){
            try {
                $filterStr = 'any(email,["'.$email.'"])';
                $getListProfilesResponse = $klaviyoClient->Lists->getListProfiles($klaviyo_list, [], ["email"], $filterStr);
                if (!empty($getListProfilesResponse)) {
                    $membershipsArray = $getListProfilesResponse['data'];
                }
            } catch (ApiException $klaviyoException) {
                Log::warning($klaviyoException->getMessage(), $klaviyoException->getTrace());
            }
        }

        $isSubscribed = count($membershipsArray) > 0;
//        KlaviyoListSubscriptionResult::createAndSave($klaviyo_list, $this->customer, $isSubscribed, json_encode($membershipsArray), $this);

        return $isSubscribed;
    }

    /**
     * @param array $fields
     * @return array|mixed
     */
    public function getKlaviyoProfile (array $fields = []) {
        $client = new KlaviyoAPI($this->customer->webSilo->klaviyo_api_key);
        $filter = 'equals(email,"'.trim($this->email).'")';
        $getProfilesResponse = $client->Profiles->getProfiles(null, empty($fields) ? null : $fields, $filter);
        return $getProfilesResponse['data'] ?? [];
    }

    /**
     * @throws Exception
     */
    public function createKlaviyoProfile() {
        $client = new KlaviyoAPI($this->customer->webSilo->klaviyo_api_key);
        $properties = $this->klaviyoProfileArray;
        $profileData = new ProfileCreateQuery([
            'data' => [
                'attributes' => [
                    'email' => trim($this->email),
                    'external_id' => $this->id,
                    'properties' => $properties,
                ],
                'type' => "profile",
            ],
        ]);
        $response = $client->Profiles->createProfile($profileData);
        $newProfileId = $response['data']['id'];
        Log::info("New Klaviyo profile id $newProfileId created for user {$this->id}.");
        $this->klaviyo_profile_id = $newProfileId;
        $this->save();
        return $newProfileId;
    }

    /**
     * @param string|null $profileId
     * @throws Exception
     */
    public function updateKlaviyoProfile (string $profileId = null) {
        if (empty($profileId)) {
            $profileId = $this->klaviyo_profile_id;
        }
        if (empty($profileId)) {
            $profiles = $this->getKlaviyoProfile();
            $profile = $profiles[0];
            $profileId = $profile['id'];
            $this->klaviyo_profile_id = $profileId;
            $this->save();
        }
        $client = new KlaviyoAPI($this->customer->webSilo->klaviyo_api_key);
        $properties = $this->klaviyoProfileArray;
        $profileData = new ProfilePartialUpdateQuery([
            'data' => [
                'attributes' => [
                    'properties' => $properties,
                ],
                'type' => "profile",
                'id' => $profileId,
            ],
        ]);
        $client->Profiles->updateProfile($profileId, $profileData);
    }

    /**
     * @deprecated use createKlaviyoProfile() or updateKlaviyoProfile() instead
     */
    public function klaviyoIdentify() {
        return;
//        $client = new Klaviyo($this->customer->webSilo->klaviyo_api_key, $this->customer->webSilo->klaviyo_company_id);
//        $array = $this->klaviyoProfileArray;
//        $event = new KlaviyoProfile($array);
//
//        $response = $client->publicAPI->identify($event);
//        Log::info("Klaviyo idenfity response: " . $response);
    }

    /**
     * @deprecated use sendKlaviyoEvent() instead
     */
    public function klaviyoTrack($metricName, $properties) {
        return;
//        $client = new Klaviyo($this->customer->webSilo->klaviyo_api_key, $this->customer->webSilo->klaviyo_company_id);
//
//        $event = new KlaviyoEvent([
//            'event' => $metricName,
//            'customer_properties' => [
//                'id' => $this->id,
//                '$email' => $this->email
//            ],
//            'properties' => $properties,
//        ]);
//
//        $client->publicAPI->track($event);
    }

    public function sendKlaviyoEvent (string $eventName, array $properties = [], string $profileId = null) {
        $client = new KlaviyoAPI($this->customer->webSilo->klaviyo_api_key);
        $eventBody = new EventCreateQueryV2([
            'data' => [
                'attributes' => [
                    'metric' => [
                        'data' => [
                            'attributes' => [
                                'name' => $eventName,
                            ],
                            'type' => "metric",
                        ],
                    ],
                    'profile' => [
                        'data' => [
                            'attributes' => [
                                'email' => $this->email,
                                'external_id' => $this->id,
                            ],
                            'type' => "profile",
                        ],
                    ],
                ],
                'type' => "event",
            ],
        ]);
        if (empty($profileId)) {
            $profileId = $this->klaviyo_profile_id;
        }
        if (!is_null($profileId)) $eventBody['data']['attributes']['profile']['data']['id'] = $profileId;
        if (count($properties)) $eventBody['data']['attributes']['properties'] = $properties;
        $client->Events->createEvent($eventBody);
    }

    /**
     * @param string|null $profileId
     * @return false|void
     */
    public function klaviyoListSubscribeWithConsent (string $profileId = null) {
        $webSilo = Arr::get($this, 'customer.webSilo');
        if (is_null($webSilo)) return false;
        $listId = Arr::get($webSilo, 'klaviyo_list_id', false);
        if (!$listId) return false;

        $client = new KlaviyoAPI($webSilo->klaviyo_api_key);

        $userProfile = [
            'attributes' => [
                'email' => $this->email,
                'subscriptions' => [
                    'email' => [
                        'marketing' => [
                            'consent' => "SUBSCRIBED",
                        ],
                    ],
                ],
            ],
            'type' => "profile",
        ];
        if (empty($profileId)) {
            $profileId = $this->klaviyo_profile_id;
        }
        if (!empty($profileId)) $userProfile['id'] = $profileId;

        $subscribeBody = new SubscriptionCreateJobCreateQuery([
            'data' => [
                'attributes' => [
                    'profiles' => [
                        'data' => [
                            $userProfile
                        ],
                    ],
                ],
                'relationships' => [
                    'list' => [
                        'data' => [
                            'id' => $listId,
                            'type' => "list",
                        ],
                    ],
                ],
                'type' => "profile-subscription-bulk-create-job",
            ],
        ]);
        try {
            $client->Profiles->subscribeProfiles($subscribeBody);
        } catch (Exception $exception) {
            Log::error("Klaviyo exception when trying to opt-in user {$this->id} for marketing list $listId, ".$exception->getMessage(), $exception->getTrace());
        }

        Log::info("User {$this->id} successfully opted-in to Klaviyo marketing list $listId");
    }

    public function webOrders(): HasMany {
        return $this->hasMany(Order::class, 'webuser_id');
    }

    /**
     * Get most recent Order based on order_date
     * @return HasOne|Order
     */
    public function latestWebOrder(): HasOne {
        return $this->hasOne(Order::class, "webuser_id")->latest("order_date");
    }

    /**
     * @return string
     */
    public static function getActiveUserPermittedDivisionsString(): string {
        $activeUser = auth()->user();
        $permittedDivisions = $activeUser->divisionPermissions()->pluck('slug')->toArray();
        if (empty($permittedDivisions)) {
            $permittedDivisions = 'NO DIVISION PERMISSIONS';
        } else {
            $permittedDivisions = implode("','", $permittedDivisions);
        }
        return $permittedDivisions;
    }

    public function sendPasswordResetNotification($token) {
        if (is_null($this->customer)) {
            $host = URL::getRequest()->getHttpHost();
            $webUrl = WebUrl::where('url', $host)->first();
            if (isset($webUrl)) {
                $webSilo = $webUrl->webSilo;
                if (isset($webSilo)) {
                    if (!is_null($webSilo->defaultLanguage())) {
                        $langObj = $webSilo->defaultLanguage();
                    } else {
                        $langObj = $webSilo->allowedLanguages->first();
                    }
                    $appName = $webSilo->display_name;
                }
            }

            if (empty($langObj)) {
                $langCode = AvailableLanguage::DEFAULT_LANG_CODE;
            } else {
                $langCode = $langObj->language_code;
            }

            if (empty($appName)) $appName = "Hilco Vision";

            $this->notify(new HilcoResetPasswordNotification($token, $langCode, $appName));
            return;
        }

        $userDefaultWebSilo = $this->customer->webSilo;
        $appName = $userDefaultWebSilo->display_name;
        if (!is_null($userDefaultWebSilo->defaultLanguage())) {
            $langObj = $userDefaultWebSilo->defaultLanguage();
        } else {
            $langObj = $userDefaultWebSilo->allowedLanguages->first();
        }
        if (is_null($langObj)) {
            $langCode = app()->getLocale();
        } else {
            $langCode = $langObj->language_code;
        }
        $this->notify(new HilcoResetPasswordNotification($token, $langCode, $appName));
    }

    public function scopeWithHubSpotContact ($query) {
        return $query->whereNotNull('hubspot_contact_id');
    }

    public function scopeWithoutHubSpotContact ($query) {
        return $query->whereNull('hubspot_contact_id');
    }

    use HasCommitSequence, BypassWith;
}