<?php

namespace StevenBuehner\sbChurchtoolsGrouphomepage\Controller;


use StevenBuehner\sbChurchtoolsGrouphomepage\Vendor\Firebase\JWT\BeforeValidException;
use StevenBuehner\sbChurchtoolsGrouphomepage\Vendor\Firebase\JWT\ExpiredException;
use StevenBuehner\sbChurchtoolsGrouphomepage\Vendor\GuzzleHttp\Exception\RequestException;
use StevenBuehner\ChurchTools\ApiException;
use StevenBuehner\sbChurchtoolsGrouphomepage\Always\MyContainer;
use StevenBuehner\sbChurchtoolsGrouphomepage\Controller\AbstractController;
use StevenBuehner\sbChurchtoolsGrouphomepage\Service\CtNewsletterService;
use StevenBuehner\sbChurchtoolsGrouphomepage\Service\Exceptions\InvalidArgumentException;
use StevenBuehner\sbChurchtoolsGrouphomepage\Service\Exceptions\LoginException;
use StevenBuehner\sbChurchtoolsGrouphomepage\Service\Exceptions\SecurityIssueException;
use StevenBuehner\sbChurchtoolsGrouphomepage\Service\Models\NewsletterBlockSettings;
use StevenBuehner\sbChurchtoolsGrouphomepage\Service\NewsletterServiceInterface;

/**
 * The public-facing functionality of the plugin.
 *
 * @link       http://example.com
 * @since      1.0.0
 *
 * @package    sbChurchtoolsGrouphomepage
 */

/**
 * The public-facing functionality of the plugin.
 *
 * Defines the plugin name, version, and two examples hooks for how to
 * enqueue the public-facing stylesheet and JavaScript.
 *
 * @author     Steven Buehner <buehner@me.com>
 */
class NewsletterFrontendController extends AbstractController {

	const action_verify_mail             = 'sb_ct_nl_verify_mail';
	const action_show_newslettersettings = 'sb_ct_nl_show_my_newslettersettings';
	const action_save_newslettersettings = 'sb_ct_nl_save_my_newslettersettings';
	const action_register_person         = 'sb_ct_nl_register_person';

	const HANDLE = 'sb-churchtools-newsletter-';

	protected function init(): void {

		$this->setUpHooks(
			FALSE,
			FALSE,
			FALSE,
			TRUE,
			FALSE,
			TRUE,
			TRUE
		);

		$this->domain = 'sb-ct-blocks';

	}


	/**
	 * Initialize the class and set its properties.
	 *
	 * @param string $domain The name of the plugin.
	 * @param string $version The version of this plugin.
	 * @param bool $debugMode
	 * @param NewsletterServiceInterface $newsletterService
	 * @since    1.0.0
	 */
	public function __construct(string $domain, string $version, bool $debugMode, protected NewsletterServiceInterface $newsletterService) {
		parent::__construct($domain, $version, $debugMode);
	}


	public function registerGutenbergBlocksAndCategories() {
		parent::registerGutenbergBlocksAndCategories();

		// Domain: sb-ct-blocks
		// Handle: sb-churchtools-countdown-editor-script
		// WordPress will check for a file in that path with the format ${domain}-${locale}-${handle}.json as the source of translations.
		$this->registerBlockJson(__DIR__ . '/../../build/Newsletter', TRUE, TRUE);

	}

	public function enqueuePublicBlockAssets() {
		if (count($this->registeredBlocks) > 0) {
			$block   = &$this->registeredBlocks[0];
			$handles = array_merge($block->editor_script_handles, $block->view_script_handles);

			foreach ($handles as $handle) {
				wp_localize_script($handle, 'sb_ct_nl', [
					'rest_all_nl'             => rest_url('churchtools/newsletter/v1/available'),
					'jwt_landingpage'         => $this->newsletterService->encodeJWT(['url' => get_permalink()]),
					'rest_account_newsletter' => rest_url('churchtools/newsletter/v1/'),
					'rest_register_user'      => rest_url('churchtools/newsletter/v1/register/person'),
					'dataprivacy_url'         => $this->newsletterService->getChurchToolsPrivacyUrl(),
					'is_debug'                => MyContainer::getSingleton()['debugMode']
				]);
			}
		}
	}


	public function registerRestRequests() {
		parent::registerRestRequests();

		if (current_user_can('edit_posts')) {
			register_rest_route('churchtools/newsletter/v1', 'system-check', [
				'methods'             => \WP_REST_Server::READABLE,
				'callback'            => [$this, 'action_get_newsletter_settings'],
				'args'                => array(),
				'permission_callback' => function ($request) {
					// Nur eingeloggte Nutzer
					// Funktioniert nur mit mitgesendeter Wordpress nonce
					return is_user_logged_in() && current_user_can('edit_posts');;

					// return current_user_can('edit_post', $postId);
				},
			]);
		}

		if (current_user_can('edit_posts')) {
			register_rest_route('churchtools/newsletter/v1', '/grouptypes/all', [
				'methods'             => \WP_REST_Server::READABLE,
				'callback'            => [$this, 'action_show_all_selectable_grouptypes'],
				'args'                => [],
				'permission_callback' => function ($request) {
					// Nur eingeloggte Nutzer
					// Funktioniert nur mit mitgesendeter Wordpress nonce
					return is_user_logged_in() && current_user_can('edit_posts');
				},
			]);
		}

		if (current_user_can('edit_posts')) {
			register_rest_route('churchtools/newsletter/v1', '/groups/(?P<id>[0-9]+)', [
				'methods'             => \WP_REST_Server::READABLE,
				'callback'            => [$this, 'action_get_groups_by_grouptype'],
				'args'                => [
					'id' => [
						'description' => 'Group Type ID',
						'type'        => 'integer',
						'required'    => TRUE,
					],
				],
				'permission_callback' => function ($request) {
					// Nur eingeloggte Nutzer
					// Funktioniert nur mit mitgesendeter Wordpress nonce
					return is_user_logged_in() && current_user_can('edit_posts');;
				},
			]);
		}

		register_rest_route('churchtools/newsletter/v1', 'verify/email', [
			'methods'             => \WP_REST_Server::CREATABLE,
			'callback'            => [$this, 'action_verify_mail'],
			'args'                => array(
				'email'           => [
					'description'       => 'E-Mail address',
					'type'              => 'string',
					'sanitize_callback' => 'sanitize_email',
					'validate_callback' => 'is_email',
					'required'          => TRUE,
				],
				'jwt_landingpage' => [
					'description'       => 'Encrypted token to verify Submission and Landingpage',
					'type'              => 'string',
					'sanitize_callback' => function ($value) {
						$value = trim($value);
						$value = $this->newsletterService->decodeJWT($value);

						if (is_array($value) && isset($value['url']) && !empty($value['url'])) {
							return $value['url'];
						}

						throw new InvalidArgumentException('Landingpage as JWT-token is invalid');
					},
					'required'          => TRUE,
				],
				'firstname'       => [
					'description'       => 'Firstname to verify newsletter support',
					'type'              => 'string',
					'sanitize_callback' => function ($word) {
						return trim($word);
					},
					'default'           => '',
					'required'          => FALSE,

				],
				'lastname'        => [
					'description'       => 'Lastname to verify newsletter support',
					'type'              => 'string',
					'sanitize_callback' => function ($word) {
						return trim($word);
					},
					'default'           => '',
					'required'          => FALSE,
				],
			),
			'permission_callback' => '__return_true',
		]);

		register_rest_route('churchtools/newsletter/v1', '/available', [
			'methods'             => \WP_REST_Server::READABLE,
			'callback'            => [$this, 'action_show_available_newsletters'],
			'args'                => [],
			'permission_callback' => '__return_true',
		]);

		register_rest_route('churchtools/newsletter/v1', '(?P<token>([-0-9a-zA-Z=_]+\.){2}[-0-9a-zA-Z=_]+)', [
			'methods'             => \WP_REST_Server::READABLE,
			'callback'            => [$this, 'action_show_my_newslettersettings'],
			'args'                => array(
				'token' => [
					'description'       => 'Token containing credentials for newslettersettings',
					'type'              => 'string',
					'validate_callback' => '__return_true',
					'required'          => TRUE
				]
			),
			'permission_callback' => '__return_true',
		]);

		register_rest_route('churchtools/newsletter/v1', '(?P<token>([-0-9a-zA-Z=_]+\.){2}[-0-9a-zA-Z=_]+)', [
			'methods'             => \WP_REST_Server::EDITABLE,
			'callback'            => [$this, 'action_save_my_newslettersettings'],
			'args'                => array(
				'changes' => [
					'description'       => 'Newsletter-Changes',
					'validate_callback' => function ($param, $request, $key) {
						if (!is_array($param)) {
							return FALSE;
						}

						foreach ($param as $id => $val) {
							if (!is_numeric($id) || !is_bool($val)) {
								return FALSE;
							}
						}


						return TRUE;
					},
					'default'           => '',
					'required'          => TRUE,
				],
				'userId'  => [
					'description'       => 'ChurchTools User-ID to change',
					'type'              => 'integer',
					'validate_callback' => 'rest_is_integer',
					'required'          => TRUE,
				]
			),
			'permission_callback' => '__return_true',
		]);

		register_rest_route('churchtools/newsletter/v1', 'register/person', [
			'methods'             => \WP_REST_Server::CREATABLE,
			'callback'            => [$this, 'action_register_person'],
			'args'                => array(
				'token'                => [
					'description' => 'Via E-Mail verified token of the users email',
					'type'        => 'string',
					'default'     => '',
					'required'    => TRUE
				],
				'email'                => [
					'description'       => 'Email, must match with token',
					'type'              => 'string',
					'sanitize_callback' => 'sanitize_email',
					'validate_callback' => 'is_email',
					'required'          => TRUE
				],
				'firstname'            => [
					'description'       => 'Firstname to verify newsletter support',
					'type'              => 'string',
					'sanitize_callback' => function ($word) {
						return trim($word);
					},
					'validate_callback' => function ($param, $request, $key) {
						return strlen(trim($param)) >= 3;
					},
					'default'           => '',
					'required'          => TRUE
				],
				'dataprivacy_accepted' => [
					'description'       => 'Value needs to be true',
					'type'              => 'boolean',
					'sanitize_callback' => function ($word) {
						return $word;
					},
					'validate_callback' => function ($param, $request, $key) {
						return $param === TRUE;
					},
					'default'           => '',
					'required'          => TRUE
				],
				'lastname'             => [
					'description'       => 'Lastname to verify newsletter support',
					'type'              => 'string',
					'sanitize_callback' => function ($word) {
						return trim($word);
					},
					'validate_callback' => function ($param, $request, $key) {
						return strlen(trim($param)) >= 3;
					},
					'default'           => '',
					'required'          => TRUE
				]
			),
			'permission_callback' => '__return_true',
		]);

	}

	public function action_get_newsletter_settings(\WP_REST_Request $request) {

		$response = [
			'mailer'      => MyContainer::getMailer()->credentialsValid(),
			'churchtools' => FALSE
		];

		try {
			$client                  = MyContainer::churchToolsLogin();
			$response['churchtools'] = TRUE;
		} catch (LoginException $e) {

		}

		return $response;

	}

	public function action_show_all_selectable_grouptypes(\WP_REST_Request $request) {

		$result = [];

		try {
			$result['success'] = TRUE;
			$result['data']    = $this->newsletterService->getAllGroupTypes();

		} catch (\Exception $e) {
			$result['success'] = FALSE;
			$result['error']   = 'Unknown Error';
		}

		return $result;

	}

	public function action_get_groups_by_grouptype(\WP_REST_Request $request) {

		$id     = (int)$request->get_param('id');
		$result = [];

		try {
			$result['success'] = TRUE;
			$result['data']    = $this->newsletterService->getAllNewsletterGroupCandidates($id);

		} catch (\Exception $e) {
			$result['success'] = FALSE;
			$result['error']   = __('Not able to load groups of this grouptype from ChurchTools', $this->domain);
		}

		return $result;

	}


	public function action_verify_mail(\WP_REST_Request $request) {

		$mail            = $request->get_param('email');
		$firstname       = $request->get_param('firstname');
		$lastname        = $request->get_param('lastname');
		$landingpage_url = rtrim($request->get_param('jwt_landingpage'), '/');

		$result = [
			'success' => TRUE,
			'data'    => [],
			'error'   => ''
		];

		$postId     = url_to_postid($landingpage_url);
		$nlSettings = new NewsletterBlockSettings($postId);

		$variables = [
			'landingpage' => $landingpage_url,
			'firstname'   => $firstname,
			'lastname'    => $lastname,
		];

		try {
			$result['data'] = $this->newsletterService->sendEmailVerification($mail, $nlSettings, $variables);
		} catch (\Exception $e) {
			$result['success'] = FALSE;
			$result['error']   = __('E-Mail verification could not be send.', $this->domain);
		}

		return $result;
	}


	public function action_show_my_newslettersettings(\WP_REST_Request $request) {

		$token    = $request->get_param('token');
		$response = [
			'success' => TRUE,
			'data'    => [
				'accounts'  => [],
				'email'     => '',
				'firstname' => '',
				'lastname'  => ''
			],
		];

		try {

			$data                      = $this->newsletterService->decodeJWT($token);
			$response['data']['email'] = $data['email'];

			// Not implemented/used yet
			if (isset($data['firstname'])) {
				$response['data']['firstname'] = $data['firstname'];
			}

			// Not implemented/used yet
			if (isset($data['lastname'])) {
				$response['data']['lastname'] = $data['lastname'];
			}

			// PostId
			$postId  = $data['pid'] ?? NULL;
			$blockId = $data['bid'] ?? NULL;

			if (empty($postId)) {
				throw new SecurityIssueException('Missing PID in Token');
			}

			$nlSettings                   = new NewsletterBlockSettings($postId, $blockId);
			$response['data']['accounts'] = $this->newsletterService->getRegisteredAccountNewsletters($data['email'], $nlSettings);

		} catch (ApiException $e) {
			$response['success'] = FALSE;
			$response['error']   = 'ChurchTools API Exception';
		} catch (\Exception $e) {
			$response['success'] = FALSE;
			$response['error']   = $e->getMessage();
		}

		return $response;

	}

	public function action_show_available_newsletters(\WP_REST_Request $request) {
		$response = [
			'success' => TRUE,
			'data'    => [],
		];

		try {
			$response['data'] = $this->newsletterService->getAllAvailableNewsletter();
		} catch (RequestException $e) {
			$response['error']   = 'ChurchTools Request Exception - ist der Zugang im Backend noch nicht konfiguriert?';
			$response['success'] = FALSE;
		} catch (\Error $e) {
			$response['error']   = 'Ein unbekannter Fehler ist aufgetreten! '; // . $e->getMessage();
			$response['success'] = FALSE;
		}
		return $response;
	}

	public function action_save_my_newslettersettings(\WP_REST_Request $request) {

		$token   = $request->get_param('token');
		$userId  = $request->get_param('userId');
		$changes = $request->get_param('changes');

		$response = [
			'success' => TRUE,
			'data'    => [],
		];

		try {
			$data = $this->newsletterService->decodeJWT($token);
		} catch (\Exception $e) {
			$response['success'] = FALSE;
			$response['error']   = 'Invalid Token';
			return $response;
		}

		// PostId
		$postId     = $data['pid'] ?? NULL;
		$blockId    = $data['bid'] ?? NULL;
		$nlSettings = new NewsletterBlockSettings($postId, $blockId);

		try {
			$currentAccounts = $this->newsletterService->getRegisteredAccountNewsletters($data['email'], $nlSettings);
			$foundAccount    = NULL;

			// Look for account
			foreach ($currentAccounts as $account) {
				if (isset($account['id']) && $account['id'] === $userId) {
					$foundAccount = $account;
					break;
				}
			}

			if ($foundAccount === NULL) {
				$response['success'] = FALSE;
				$response['error']   = 'Security-Issue: Token is not matching with userId!';
				return $response;
			}

		} catch (\Exception $e) {
			$response['success'] = FALSE;
			$response['error']   = 'Impossible to load ChurchTools Newsletter from account-token.';
			return $response;
		}

		$changesAllSuccessfull = TRUE;
		foreach ($changes as $newsletterId => $change) {

			$newsleterIdForAction = NULL;

			foreach ($foundAccount['newsletter'] as $nl) {
				if ($nl['id'] === $newsletterId) {
					$newsleterIdForAction = $nl['id'];
					break;
				}
			}

			if ($change === TRUE) {
				$changesAllSuccessfull = $changesAllSuccessfull && $this->newsletterService->subscribe($nlSettings, $newsleterIdForAction, $userId);
			} else {
				$changesAllSuccessfull = $changesAllSuccessfull && $this->newsletterService->unsubscribe($nlSettings, $newsleterIdForAction, $userId);
			}

		}

		$response['success'] = $changesAllSuccessfull;

		return $response;

	}

	public function action_register_person(\WP_REST_Request $request) {

		$token                = $request->get_param('token');
		$dataprivacy_accepted = $request->get_param('dataprivacy_accepted');
		$email                = $request->get_param('email');
		$firstname            = $request->get_param('firstname');
		$lastname             = $request->get_param('lastname');

		$response = [
			'success' => FALSE,
			'data'    => [],
		];

		try {
			$data = $this->newsletterService->decodeJWT($token);
		} catch (ExpiredException $e) {
			$response['error'] = $e->getMessage();
			return $response;
		} catch (BeforeValidException $e) {
			$response['error'] = $e->getMessage();
			return $response;
		} catch (\Exception $e) {
			$response['error'] = 'Invalid Token';
			return $response;
		}


		if ($data['email'] !== $email) {
			$response['error'] = 'Security issue: given email does not match token';
			return $response;
		}

		if ($dataprivacy_accepted !== TRUE) {
			$response['error'] = 'Missing requirement: Dataprivacy was not accepted.';
			return $response;
		}


		try {
			$person = $this->newsletterService->registerNewChurchtoolsPerson($email, $firstname, $lastname);
		} catch (\Exception $e) {
			$response['error'] = 'API-ERROR - Could not register person';
			return $response;
		}

		// PostId
		$postId     = $data['pid'] ?? NULL;
		$blockId    = $data['bid'] ?? NULL;
		$nlSettings = new NewsletterBlockSettings($postId, $blockId);

		$accounts = $this->newsletterService->getRegisteredAccountNewsletters($email, $nlSettings);

		$response['success'] = TRUE;
		$response['data']    = [
			'accounts'  => $accounts,
			'email'     => $email,
			'firstname' => $firstname,
			'lastname'  => $lastname
		];


		return $response;
	}


}
