<?php

/**
 * Class MailChimp_WooCommerce_Subscriber_Sync
 */
class MailChimp_WooCommerce_Subscriber_Sync extends Mailchimp_Woocommerce_Job
{
    public $data = array();

    /**
     * SubscriberSync constructor.
     * Pass in the raw data from the webhook from Mailchimp
     * @param $data
     */
    public function __construct($data)
    {
        $this->data = (array) $data;
    }

    /**
     * @return bool|null
     */
    public function handle()
    {
        try {
            // if the store is not properly connected to Mailchimp - we need to skip this.
            if (!mailchimp_is_configured()) {
                mailchimp_log('subscriber_sync', 'Mailchimp is not configured, can not process job.');
                return null;
            }
            // grab the hook type, and the new data
            list($hook_type, $data, $failed) = $this->parseInputData();
            // extract the service ids from the data we get
            list ($service_id, $email) = $this->extractServiceIDs($data);
            // ignore the empty submissions or certain events or emails
            if ($this->hasInvalidEvent($hook_type, $failed, $data)) {
                mailchimp_log('subscriber_sync', 'Webhook has invalid event', compact('email'));
                return false;
            }
            if ($this->shouldIgnoreEmail($email)) {
                mailchimp_log('subscriber_sync', 'Webhook is ignoring email', compact('email'));
                return false;
            }
            // if hook type is 'subscribe' that means we need ot subscribe them
            $subscribe = $hook_type === 'subscribe';
            // if we don't have a user by email
            if (!($user = get_user_by('email', $email))) {
                // if the user is not found and we should create new customers
                return ($subscribe && $this->shouldCreateNewCustomers()) ?
                    (bool) $this->createNewCustomer($email) :
                    false;
            }
            try {
                $handled_key = "subscriber_sync.{$service_id}.handled";
                // see if we've saved a service call in the last 30 minutes.
                $handled = mailchimp_get_transient($handled_key);
                // if we've got the subscriber sync id and it's the same as the previous submission, just skip out now.
                if ($handled === $subscribe) {
                    mailchimp_log('subscriber_sync', "didn't need to do anything");
                    return true;
                }
                // if they unsubscribed, we need to put a cache on this because it's causing issues in the
                // shopify webhooks for some reason being re-subscribed.
                if (!$subscribe) {
                    // update the cached status just in case this is causing trouble with the webhook.
                    $hashed = md5(trim(strtolower($email)));
                    // tell the webhooks that we've just synced this customer with a certain status.
                    mailchimp_set_transient("{$hashed}.subscriber_sync", array('time' => time(), 'status' => false), 90);
                }
                // update the user meta to show the proper value.
                update_user_meta($user->ID, 'mailchimp_woocommerce_is_subscribed', $subscribe);
                // cache it for 90 seconds to be used above.
                mailchimp_set_transient($handled_key, $subscribe, 90);
                mailchimp_log('webhook', "Subscriber Sync :: {$hook_type} :: {$email}", array(
                    'subscribed' => $subscribe,
                    'user_id' => $user->ID,
                ));
                return true;
            } catch (Exception $e) {
                $error = $e->getMessage();
                mailchimp_error('webhook', "Updating Subscriber Status :: MC service ID {$service_id} :: {$hook_type} :: {$error}");
                return false;
            }
        } catch (Throwable $e) {
            mailchimp_error('webhook', $e->getMessage(), array(
            	'data' => isset($data) && $data ? json_encode($data) : null
            ));
        }
        return false;
    }

    /**
     * @param $data
     * @return array
     */
    private function extractServiceIDs($data)
    {
        if (is_object($data)) {
            $service_id = isset($data->web_id) ?
                $data->web_id :
                (isset($data->id) ? $data->id : null);
            $email = isset($data->email) ? $data->email : null;
            return array($service_id, $email);
        } else {
            $service_id = isset($data['web_id']) ? $data['web_id'] : false;
            if (!$service_id) {
                $service_id = isset($data['id']) ? $data['id'] : false;
            }
            $email = isset($data['email']) ? $data['email'] : false;
            return array($service_id, $email);
        }
    }

    /**
     * @return array
     */
    private function parseInputData()
    {
        $hook_type = isset($this->data['type']) ? $this->data['type'] : 'certainly_not';
        $data = isset($this->data['data']) ? $this->data['data'] : [];
        $failed = false;
        $allowed_hooks = array('subscribe' => true, 'unsubscribe' => true,);
        if (!is_string($hook_type) || !isset($allowed_hooks[$hook_type])) {
            $failed = true;
        }
        return array($hook_type, $data, $failed);
    }

	/**
	 * @param $email
	 *
	 * @return int|WP_Error
	 * @throws MailChimp_WooCommerce_Error
	 * @throws MailChimp_WooCommerce_RateLimitError
	 * @throws MailChimp_WooCommerce_ServerError
	 */
    private function createNewCustomer($email)
    {
        $member = mailchimp_get_api()->member(mailchimp_get_list_id(), $email);
        $first_name = !empty($member['merge_fields']['FNAME']) ? $member['merge_fields']['FNAME'] : 'Guest';
        $last_name = !empty($member['merge_fields']['LNAME']) ? $member['merge_fields']['LNAME'] : 'Customer';
        if (empty($first_name)) $first_name = null;
        if (empty($last_name)) $last_name = null;
        // TODO maybe use the registration method and keep a record for when the user is verified later
        $user = wp_create_user(strtolower($email), wp_generate_password(), strtolower($email));
        // subscribe them because this function only runs for subscribers.
        update_user_meta($user, 'mailchimp_woocommerce_is_subscribed', true);
        // if we have a first and last name from the MC account, just use that.
        if ($first_name && $last_name) {
            wp_update_user(array(
                'ID' => $user,
                'first_name' => $first_name,
                'last_name' => $last_name
            ));
        }
        mailchimp_log('webhook', "CREATED CUSTOMER :: {$email} :: {$first_name} {$last_name}");
        return $user;
    }

    /**
     * @return false
     */
    private function shouldCreateNewCustomers()
    {
        // maybe we add a setting for this in the UI and use this here.
        return false;
    }

    /**
     * @param $email
     * @return bool
     */
    private function shouldIgnoreEmail($email)
    {
        return mailchimp_string_contains($email, array(
            'forgotten.mailchimp.com'
        ));
    }

    /**
     * @param $hook_type
     * @param $failed
     * @param $data
     * @return bool
     */
    private function hasInvalidEvent($hook_type, $failed, $data)
    {
        if (empty($hook_type) || empty($data)) {
            return true;
        }
        // if the flag is failed, or deleted, don't do anything.
        if ($failed || $hook_type === 'deleted' || $hook_type === 'delete') {
            return true;
        }
        return false;
    }
}
