<?php

namespace Mtc\Plugins\NewsletterSignup\Classes;

use App\Src\Encryption;
use Illuminate\Support\Facades\App;
use Illuminate\Support\Facades\DB;

/**
 * Class NewsletterSignUp
 * Default Newsletter sign-up driver
 *
 * @package Mtc\Plugins\NewsletterSignup\Classes
 * @author Martins Fridenbergs <martins.fridenbergs@mtcmedia.co.uk>
 * @author Uldis Zvirbulis <uldis.zvirbulis@mtcmedia.co.uk>
 */
class NewsletterSignUp implements SignUpInterface
{
    /**
     * Double opt-in status for success
     */
    const ACTIVATE_STATUS_SUCCESS = 0;
    /**
     * Double opt-in status for already activated
     */
    const ACTIVATE_STATUS_ALREADY_ACTIVATED = 1;

    /**
     * Double opt-in status for incorrect hash
     */
    const ACTIVATE_STATUS_WRONG_HASH = 2;

    /**
     * @var string[] $statuses List of available statuses for newsletter subscription activation
     */
    public static $statuses = [
        self::ACTIVATE_STATUS_SUCCESS => 'success',
        self::ACTIVATE_STATUS_ALREADY_ACTIVATED => 'already_activated',
        self::ACTIVATE_STATUS_WRONG_HASH => 'wrong_hash',
    ];

    /**
     * @var string $salt salt for encrypting double opt-in hash
     */
    public static $salt = 'QZNfHmANqMm8swRjsxS3&@!#_';

    /**
     * @var string name of the newsletter list in DB
     */
    public static $newsletter_list_name = 'newsletter_list';

    /**
     * @var bool|int $newsletter_list_id ID of the newsletter sign-up list in DB
     */
    private $newsletter_list_id = false;

    /**
     * CampaignMonitor constructor.
     * Initializes the connection with CampaignMonitor API
     */
    public function __construct($newsletter_list_id)
    {
        $this->newsletter_list_id = $newsletter_list_id;
    }

    /**
     * Action sign-up of a newsletter on site using the DB list
     *
     * @param string $email email address to sign up
     * $param array $additional_params any additional params passed to interface
     * @throws \Exception Unsuccessful sign-up message
     * @return mixed
     */
    public function signUp($email, $additional_params = [])
    {
        if (! empty($additional_params['skip_double_opt_in'])) {
            if ($this->checkIfExists($email)) {
                return true;
            }

            // All validated, add the email to the newsletter list
            MailList::query()
                ->create([
                    'list_id' => $this->newsletter_list_id,
                    'email' => $email,
                    'firstname' => $additional_params['first_name'] ?? '',
                    'surname' => $additional_params['last_name'] ?? '',
                ]);

            return true;
        }

        // Remove previous sign-up to clean
        DoubleOptInEmail::query()
            ->where('email_hash', Encryption::makeHash($email))
            ->delete();

        DoubleOptInEmail::query()
            ->create([
                'email' => $email,
                'firstname' => $additional_params['first_name'] ?? '',
                'surname' => $additional_params['last_name'] ?? '',
            ]);

        return true;
    }

    /**
     * Check if user already exists in CM database
     * Used to ensure user isn't subscribed multiple times
     *
     * @param $email
     * @return bool
     */
    public function checkIfExists($email)
    {
        return MailList::query()
            ->where('list_id', $this->newsletter_list_id)
            ->where('email_hash', Encryption::makeHash($email))
            ->exists();
    }

    /**
     * Try to activate newsletter subscription. Returns status
     *
     * @param string $hash Hash that's in activation URL
     * @return int Status
     */
    public function activate($hash)
    {
        if (empty($hash)) {
            return self::ACTIVATE_STATUS_WRONG_HASH;
        }

        // If email is already in the list
        $exists_in_list = MailList::query()
            ->withHash($hash)
            ->where('list_id', $this->newsletter_list_id)
            ->exists();

        if ($exists_in_list) {
            DoubleOptInEmail::query()
                ->withHash($hash)
                ->delete();

            return self::ACTIVATE_STATUS_ALREADY_ACTIVATED;
        }

        // If there's no such email by hash in buffer table
        $double_opt_in_email = DoubleOptInEmail::query()
            ->withHash($hash)
            ->first();

        if (! $double_opt_in_email) {
            return self::ACTIVATE_STATUS_WRONG_HASH;
        }

        // All validated, add the email to the newsletter list
        MailList::query()
            ->create([
                'list_id' => $this->newsletter_list_id,
                'email' => $double_opt_in_email->email,
                'firstname' => $double_opt_in_email->firstname,
                'surname' => $double_opt_in_email->surname,
            ]);

        // Remove email from the buffer table
        $double_opt_in_email->delete();

        return self::ACTIVATE_STATUS_SUCCESS;
    }

    /**
     * Send out an email for Double Opt-in. Email contains activation link with hash
     *
     * @param DoubleOptInEmail $double_opt_in Information about the user that requested sign-up
     * @throws \Exception
     * @return bool
     */
    public static function sendActivationEmail(DoubleOptInEmail $double_opt_in)
    {
        // Fetch twig instance
        $twig = App::make('twig');

        $mail = $twig->render('/emails/email_double_optin.twig', [
            'subscriber' => $double_opt_in,
            'activation_url' =>
                SITE_URL
                    .'/plugins/NewsletterSignup/index.php?newsletter_action=activate&hash='
                    .md5($double_opt_in->email.self::$salt),
        ]);

        $subject = 'Welcome to '.config('app.name').' Newsletter';

        email($double_opt_in->email, $subject, $mail);

        return true;
    }

    /**
     * Try to activate users newsletter subscription
     * returns status in text format
     *
     * @param string $hash submitted hash
     * @return string activation status
     */
    public static function activateAndGetPrettyStatus($hash)
    {
        /** @var self $sign_up Initialize the sign up class */
        $sign_up = App::make(self::class);
        $activation_status = $sign_up->activate($hash);

        // return text based status
        return self::$statuses[$activation_status];
    }

    /**
     * Try to unsubscribe users newsletter subscription
     *
     * @param string $email email address to unsubscribe
     *
     * @return mixed
     */
    public function unsubscribe($email)
    {
        return MailList::query()
            ->where('email_hash', Encryption::makeHash($email))
            ->delete();
    }
}
