<?php
namespace SabaiApps\Directories\Component\Dashboard\Helper;

use SabaiApps\Directories\Application;
use SabaiApps\Directories\Exception;
use SabaiApps\Directories\Request;
use SabaiApps\Directories\Component\Entity\Type\IEntity;

class GuestAccessHelper {

	const DEFAULT_DURATION = 7;

	public function isEnabled( Application $application ) {
		return (bool) $application->getComponent( 'Dashboard' )->getConfig( 'guest_access', 'enable' );
	}

	public function isGranted( Application $application, $checkEnabled = true ) {
		if ( ( ! $checkEnabled || $this->isEnabled( $application ) )
			&& ( $var = $application->getPlatform()->getSessionVar( 'dashboard_guest_access' ) )
			&& ! empty( $var['email'] )
		) {
			return $var['email'];
		}
		return false;
	}

	public function grant( Application $application, $email ) {
		$application->getPlatform()->setSessionVar( 'dashboard_guest_access', array( 'email' => $email ) );
	}

	public function revoke( Application $application ) {
		$application->getPlatform()->deleteSessionVar( 'dashboard_guest_access' );
	}

	public function duration( Application $application ) {
		return ( $duration = $application->getComponent( 'Dashboard' )->getConfig( 'guest_access', 'duration' ) ) ? $duration : self::DEFAULT_DURATION;
	}

	public function requestActivationForm( Application $application ) {
		return array(
			'email' => array(
				'#type'        => 'email',
				'#title'       => __( 'E-mail Address', 'directories-pro' ),
				'#description' => __( 'Enter the e-mail address associated with one or more of your posts.', 'directories-pro' ),
			),
		);
	}

	public function requestActivation( Application $application, $values ) {
		if ( empty( $values['email'] )
			|| ( ! $entities = $this->hasPosts( $application, $values['email'] )
			)
		) {
			throw new Exception\RuntimeException( __( 'There is no post associated with the e-mail address entered.', 'directories-pro' ) );
		}

		$entity            = array_pop( $entities );
		$entity_guest_info = $entity->getSingleFieldValue( 'frontendsubmit_guest' );
		$guid_lifetime     = 86400 * $this->duration( $application );
		if ( empty( $entity_guest_info['guid'] )
			|| $entity_guest_info['guid_created'] + $guid_lifetime < time()
		) {
			$entity_guest_info['guid']         = uniqid( '', true );
			$entity_guest_info['guid_created'] = time();
			$application->Entity_Save( $entity, array( 'frontendsubmit_guest' => $entity_guest_info ) );
		}

		$this->_sendEmail( $application, $entity_guest_info['email'], $entity_guest_info['guid'], $entity_guest_info['name'] );
	}

	public function hasPosts( Application $application, $email, $fetch = 1 ) {
		$entities = $application->Entity_Query( 'post' )
			->fieldIsIn( 'status', $this->_postStatuses( $application ) )
			->fieldIs( 'frontendsubmit_guest', $email, 'email' )
			->fetch( (int) $fetch );
		return empty( $entities ) ? false : $entities;
	}

	protected function _postStatuses( Application $application ) {
		return array( $application->Entity_Status( 'post', 'publish' ), $application->Entity_Status( 'post', 'pending' ), $application->Entity_Status( 'post', 'draft' ) );
	}

	protected function _sendEmail( Application $application, $email, $guid, $name ) {
		$tags = $this->emailTags(
			$application,
			array(
				'email' => $email,
				'guid'  => $guid,
				'name'  => $name,
			)
		);
		if ( $application->getComponent( 'Dashboard' )->getConfig( 'guest_access', 'custom_email' ) ) {
			$subject = strtr( $application->getComponent( 'Dashboard' )->getConfig( 'guest_access', 'email_subject' ), $tags );
			$body    = strtr( $application->getComponent( 'Dashboard' )->getConfig( 'guest_access', 'email_body' ), $tags );
		} else {
			list($subject, $body) = $this->defaultEmail( $application, $tags );
		}
		if ( ! $application->getPlatform()->mail( $email, $subject, $body ) ) {
			throw new Exception\RuntimeException( 'Failed sending email to ' . $email );
		}
	}

	public function defaultEmail( Application $application, ?array $tags = null ) {
		/* translators: Lost password email subject. %s: Site name */
		$subject = sprintf( __( '[%s] Guest access URL', 'directories-pro' ), isset( $tags ) ? $tags['%%site_name%%'] : '%%site_name%%' );
		$body    = sprintf( __( 'Hello %s,', 'directories-pro' ), isset( $tags ) ? $tags['%%guest_name%%'] : '%%guest_name%%' ) . "\r\n\r\n";
		$body   .= __( 'Visit the following URL to access the dashboard:', 'directories-pro' ) . "\r\n";
		$body   .= ( isset( $tags ) ? $tags['%%guest_access_url%%'] : '%%guest_access_url%%' ) . "\r\n\r\n";
		$body   .= ( isset( $tags ) ? $tags['%%site_name%%'] : '%%site_name%%' ) . "\r\n" . ( isset( $tags ) ? $tags['%%site_url%%'] : '%%site_url%%' );

		return array( $subject, $body );
	}

	public function emailTags( Application $application, ?array $guestInfo = null ) {
		if ( ! isset( $guestInfo ) ) {
			return array(
				'%%site_name%%',
				'%%site_url%%',
				'%%guest_name%%',
				'%%guest_access_url%%',
			);
		}

		return array(
			'%%site_name%%'        => $application->getPlatform()->getSiteName(),
			'%%site_url%%'         => $application->getPlatform()->getSiteUrl(),
			'%%guest_name%%'       => strlen( $guestInfo['name'] ) ? $guestInfo['name'] : __( 'Guest', 'directories-pro' ),
			'%%guest_access_url%%' => $application->Url(
				'/' . $application->getComponent( 'Dashboard' )->getSlug( 'dashboard' ) . '/request_guest_access',
				array(
					'guid'  => $guestInfo['guid'],
					'email' => $guestInfo['email'],
				),
				'',
				'&'
			),
		);
	}

	public function validateRequest( Application $application, Request $request ) {
		if ( ( ! $email = $request->asStr( 'email' ) )
			|| ( ! $guid = $request->asStr( 'guid' ) )
			|| ( ! $application->Entity_Query( 'post' )
				->fieldIsIn( 'status', $this->_postStatuses( $application ) )
				->fieldIs( 'frontendsubmit_guest', $email, 'email' )
				->fieldIs( 'frontendsubmit_guest', $guid, 'guid' )
				->fieldIsOrGreaterThan( 'frontendsubmit_guest', time() - ( 86400 * $this->duration( $application ) ), 'guid_created' )
				->count() )
		) {
			return false;
		}

		$application->getPlatform()->setSessionVar( 'dashboard_guest_access', array( 'email' => $email ) );
		return true;
	}

	public function isAuthor( Application $application, IEntity $entity ) {
		return ( $application->getUser()->isAnonymous()
			&& ! $entity->getAuthorId() // must be a guest post
			&& ( $email = $this->isGranted( $application ) )
			&& ( $guest_field_value = $entity->getSingleFieldValue( 'frontendsubmit_guest' ) )
			&& ! empty( $guest_field_value['guid'] )
			&& $guest_field_value['email'] === $email
			&& ( empty( $guest_field_value['guid_created'] ) || $guest_field_value['guid_created'] + ( 86400 * $this->duration( $application ) > time() ) )
		);
	}
}

/*
dashboard
	-> !isGranted
		-> redirect to request guest access
			-> !validateRequest -> show activation form -> send email
			-> validateRequest -> grant -> redirect to dashboard
	-> isGranted
		-> show dashboard



 */
