<?php

use Intellex\MailChimp\Exception\ValidationException;
use Newsletter\Model\CampaignModel;

class CampaignsController extends NewsletterAppController {

	/** @inheritdoc No model. */
	public $uses = [];

	/**
	 * Action: Show the list of all campaigns.
	 *
	 * @throws Exception
	 * @throws \Intellex\MailChimp\Api\ValidationException
	 */
	public function index() {
		// Set header actions
		$this->addAction('plus', __('Create new campaign'), [ P => 'newsletter', C => 'campaigns', A => 'create' ], [ 'class' => 'btn btn-success' ]);
		$this->addAction('list', __('Subscriber lists'), [ P => 'newsletter', C => 'lists', A => 'index' ]);

		// Get all Campaigns
		$count = 30;
		$campaigns = $this->mailchimp()->campaign()->getAll($this->itemOffset($count), $count);

		// Get all reports
		$reports = [];
		$reportsData = $this->mailchimp()->report()->getAll();
		foreach ($reportsData as $report) {
			$reports[$report->id] = $report;
		}

		// Set crumbs
		$this->crumbs[] = __('Campaigns');

		$this->set(compact('campaigns', 'reports'));

	}

	/**
	 * Action: Create or edit a campaign.
	 *
	 * @var string $id Unique Id used if edit existing campaign. Defaults to null.
	 * @throws Exception
	 * @throws \Intellex\MailChimp\Api\ValidationException
	 */

	public function create($id = null) {
		$template = $vars = null;

		// Set header actions
		$this->addAction('list', __('List all campaigns'), [ P => 'newsletter', C => 'campaigns', A => 'index' ], [ 'class' => 'btn btn-default' ]);
		$this->addAction('eye', __('Test'), [ P => 'newsletter', C => 'campaigns', A => 'test', $id ], [ 'class' => 'btn btn-default' ]);
		$this->addAction('calendar', __('Schedule'), [ P => 'newsletter', C => 'campaigns', A => 'schedule', $id ], [ 'class' => 'btn btn-primary' ]);
		$this->addAction('paper-plane', __('Send Now'), [ P => 'newsletter', C => 'campaigns', A => 'send', $id ], [ 'class' => 'btn btn-danger', 'confirm' => 'Are you sure?']);

		// Save submitted data
		if ($this->request->data) {

			// Create template
			$data = key_exists('TemplateVars', $this->request->data)
				? $this->request->data['TemplateVars']
				: [];

			// Parse the template
			$html = $this->printTemplate($this->request->data['template'], $data);

			$campaign = $this->save($this->request->data, $html);

			// Edit existing form
		} else if ($id) {
			$campaign = CampaignModel::build($this->mailchimp()->campaign()->get($id));
			$template = $campaign->data['template'];

			// Set the values from the template
			$campaign->data['TemplateVars'] = [];
			$content = $this->mailchimp()->campaign()->getContent($id);

			preg_match_all('~data-template-var="(?P<count>[^/]*)/(?P<name>[^/]*)/(?P<value>[^"]*)"~ Uui', $content['html'], $vars, PREG_SET_ORDER);
			foreach ($vars as $var) {

				// Decode values
				$name = urldecode($var['name']);
				$value = urldecode($var['value']);

				// Set thr values
				switch ($var['count']) {
					case 'single':
						$campaign->data['TemplateVars'][$name] = $value;
						break;

					case 'array':

						// Make sure the array is initialize
						if (!key_exists($name, $campaign->data['TemplateVars'])) {
							$campaign->data['TemplateVars'][$name] = [];
						}

						$campaign->data['TemplateVars'][$name][] = $value;
				}
			}

			// Create new
		} else {
			$campaign = new CampaignModel();
			$campaign->errors = [];
		}

		// Get lists and templates
		$path = $this->getTemplatePath();
		$lists = $this->getLists();
		$templates = $this->getTemplates();

		// Get the variables
		if ($template) {
			$vars = Newsletter\Builder\Parser::getVariables(Newsletter\Builder\Parser::getSpecification($this->getTemplate($template)));
		}

		// Set crumbs
		$this->crumbs[] = [ __('Campaigns'), [ P => 'newsletter', C => 'campaigns', A => 'index' ] ];
		$this->crumbs[] = $id && $campaign ? __('Edit campaign %s', $campaign->data['title']) : __('Create campaign');

		$this->set(compact('id', 'campaign', 'path', 'lists', 'templates', 'template', 'vars'));
	}

	/**
	 * @param array  $data The data to save.
	 * @param string $html The HTML content for the campaign.
	 *
	 * @throws Exception
	 * @throws \Intellex\MailChimp\Api\ValidationException
	 */
	private function save($data, $html = null) {
		$campaign = new CampaignModel($data);
		$this->set('campaign', $campaign);

		// Save
		try {
			if ($campaign->save($this->mailchimp())) {
				try {
					$this->mailchimp()->campaign()->setContent($campaign->data['id'], $html);

					// Set message and redirection
					$this->Session->setFlash(__('Campaign saved successfully'));
					$this->redirect([ P => 'newsletter', C => 'campaigns', A => 'create', $campaign->data['id'] ]);

				} catch (ValidationException $ex) {
					$this->set('exceptions', $ex->getErrors());
					$this->Session->setFlash(__('Campaign could not have been saved'), 'danger', false);
					$this->redirect([ P => 'newsletter', C => 'campaigns', A => 'create', $campaign->data['id'] ]);
				}

			} else {
				$this->Session->setFlash(__('Campaign saved successfully'));
			}

		} catch (ValidationException $ex) {
			$this->set('exceptions', $ex->getErrors());
			$this->Session->setFlash(__('Campaign could not have been saved'), 'danger', false);
		}
	}

	/**
	 * Action: Remove a campaign.
	 *
	 * @var string $id Unique ID of the campaign to delete.
	 * @throws Exception
	 * @throws \Intellex\MailChimp\Api\ValidationException
	 */
	public function remove($id) {
		$success = $this->mailchimp()->campaign()->delete($id);

		if ($success) {
			$this->backtrack(__('Campaign has been successfully deleted.'));
		} else {
			$this->backtrack(__('Campaign could not be deleted.'), 'danger', false);
		}
	}

	/**
	 * Action: Show a campaign preview..
	 *
	 * @var string $id Unique Id used if edit existing campaign. Defaults to null.
	 * @throws Exception
	 * @throws \Intellex\MailChimp\Api\ValidationException
	 */
	public function preview($id = null) {
		if ($id) {

			// Validate
			$campaign = CampaignModel::build($this->mailchimp()->campaign()->get($id));
			if ($campaign->errors) {
				echo 'There are some errors...';
				die;
			}

			// Define data
			$data = !empty($this->request->data['TemplateVars'])
				? $this->request->data['TemplateVars']
				: [];

			echo $this->printTemplate($campaign->data['template'], $data);
		}
		exit(0);
	}

	/**
	 * Print the template.
	 *
	 * @param string $_template The template filename, without extension.
	 * @param array  $_data     The list of all data to print.
	 *
	 * @return string The complied template.
	 */
	private function printTemplate($_template, $_data) {

		// Handle the variables
		$_vars = [];
		if (!empty($_data)) {

			// Get variables
			$vars = Newsletter\Builder\Parser::getVariables(Newsletter\Builder\Parser::getSpecification($this->getTemplate($_template)));
			foreach ($vars as $var) {
				foreach ($_data as $key => $value) {
					if ($var->getName() === $key) {
						$_vars[$key] = $var->parse($value);
					}
				}
			}
		}

		// Prepare for export
		$_vars = var_export($_vars, true);

		// Define header for the email
		$header = <<< HEADER
<?php define('MAIL_CHIMP_RENDER', true);
	
	// Show errors
	Configure::write('debug', true);
	ini_set('display_errors', true);
	error_reporting(E_ALL);
	
	// Load data
	\$_data = {$_vars};
?>

HEADER;

		// Get the template
		$tmp = tempnam(sys_get_temp_dir(), "mcc");
		file_put_contents($tmp, $header . str_replace('error_reporting', 'date', file_get_contents($this->getTemplate($_template))));

		// Evaluate
		ini_set('display_errors', true);
		error_reporting(E_ALL);

		/** @noinspection PhpIncludeInspection */
		ob_start();
		require $tmp;
		@unlink($tmp);
		return ob_get_clean();
	}

	/**
	 * Get the list of all subscriber lists.
	 *
	 * @return string[] The list of subscriber lists where key is the list id and value is list name.
	 */
	public function getLists() {
		$lists = [];

		// Load lists from mail chimp
		$listData = $this->mailchimp()->lists()->getAll();

		foreach ($listData['lists'] as $item) {
			$lists[$item->id] = $item->name;
		}

		return $lists;
	}

	/**
	 * Get the path to the templates.
	 *
	 * @return string The full path to the directory where templates are stored.
	 */
	private function getTemplatePath() {
		return APP . 'View/Emails/newsletters/';
	}

	/**
	 * Get the path to the template.
	 *
	 * @param string $templateName The filename of the template, without the extension.
	 *
	 * @return string The full path to the template.
	 */
	private function getTemplate($templateName) {
		return $this->getTemplatePath() . $templateName . '.ctp';
	}

	/**
	 * Get the list of all templates.
	 *
	 * @return string[] The list of templates where key is the filename and value is human friendly filename.
	 * @throws Exception
	 */
	private function getTemplates() {
		$templates = [];

		// Get all files
		$files = glob($this->getTemplate('*'));
		foreach ($files as $file) {

			// Make sure the file can be parsed
			if (preg_match("~/(?P<name>[a-z0-9][\.a-z0-9_-]+)\.ctp$~ i", $file, $match)) {
				$templates[$match['name']] = Inflector::humanize($match['name']);

			} else {
				throw new \Exception("Unable to parse template: `{$file}`");
			}
		}

		return $templates;
	}

	/** TODO */
	public function report($id) {
		$report = $this->mailchimp()->report()->get($id);

		$this->set(compact('report'));

	}

	/**
	 * Send The campaign immediately
	 *
	 * @param string $id The id of campaign to send
	 *
	 * @throws Exception
	 * @throws \Intellex\MailChimp\Api\ValidationException
	 */
	public function send($id) {
		try {
			$this->mailchimp()->campaign()->send($id);
			$this->Session->setFlash(__('Campaign successfully Sent'));
			$this->redirect([ P => 'newsletter', C => 'campaigns', A => 'index']);

		} catch (ValidationException $ex) {
			$this->set('exceptions', $ex->getErrors());
			$this->backtrack($ex->getDetail(), 'danger');
		};
	}

	/**
	 * Schedule Campaign
	 *
	 * @param string $id The id of campaign to schedule
	 *
	 * @throws Exception
	 * @throws \Intellex\MailChimp\Api\ValidationException
	 */
	public function schedule($id) {
		// Set header actions
		$this->addAction('pencil', __('Edit Campaign'), [ P => 'newsletter', C => 'campaigns', A => 'create', $id ], [ 'class' => 'btn btn-default' ]);
		$this->addAction('envelope', __('Test Newsletter'), [ P => 'newsletter', C => 'campaigns', A => 'test', $id ], [ 'class' => 'btn btn-default' ]);
		$data = $this->request->data;

		// Save submitted data
		if ($data) {
			try {

				if ($this->mailchimp()->campaign()->get($id)->getStatus() === 'schedule') {

					// Cannot schedule an already scheduled campaign
					$this->mailchimp()->campaign()->unSchedule($id);
				}

				// Covert to ISO time
				$time = date('c', strtotime($data['schedule_time']));
				$schedule = $this->mailchimp()->campaign()->schedule($id, $time);

				$this->Session->setFlash(__('Campaign successfully scheduled'));

			} catch (ValidationException $ex) {
				$this->set('exceptions', $ex->getErrors());
				$this->Session->setFlash($ex->getDetail(), 'danger');
			};
		}

		$campaign = CampaignModel::build($this->mailchimp()->campaign()->get($id));

		$this->set(compact('schedule', 'campaign'));

		// Set crumbs
		$this->crumbs[] = [ __('Campaigns'), [ P => 'newsletter', C => 'campaigns', A => 'index' ] ];
		$this->crumbs[] = [ __('Edit campaign'), [ P => 'newsletter', C => 'campaigns', A => 'create', $id ] ];

		$this->crumbs[] = $id && $campaign ? __('Test and send campaign %s', $campaign->data['title']) : __('Create campaign');

		$this->set(compact('id', 'campaign', 'html'));
	}

	/**
	 * Pause scheduled campaign
	 *
	 * @param $id string The id of campaign to pause
	 *
	 * @throws Exception
	 * @throws \Intellex\MailChimp\Api\ValidationException
	 */
	public function pause($id) {
		try {
			$this->mailchimp()->campaign()->unSchedule($id);
			$this->backtrack(__('Campaign has been successfully paused.'));

		} catch (ValidationException $ex) {
			$this->set('exceptions', $ex->getErrors());
			$this->Session->setFlash($ex->getDetail(), 'danger');
		};
	}

	/**
	 * Send test email to list of emails
	 *
	 * @param $id
	 *
	 * @throws Exception
	 * @throws \Intellex\MailChimp\Api\ValidationException
	 */
	public function test($id) {

		// Set header actions
		$this->addAction('pencil', __('Edit Campaign'), [ P => 'newsletter', C => 'campaigns', A => 'create', $id ], [ 'class' => 'btn btn-default' ]);
		$this->addAction('calendar', __('Send Newsletter'), [ P => 'newsletter', C => 'campaigns', A => 'send', $id ], [ 'class' => 'btn btn-default' ]);
		$data = $this->request->data;

		$campaign = CampaignModel::build($this->mailchimp()->campaign()->get($id));

		// Save submitted data
		if ($data) {
			try {
				$this->mailchimp()->campaign()->test($id, explode(',', $data['test_emails']));

				$this->Session->setFlash(__('Test email sent'));

			} catch (ValidationException $ex) {
				$this->set('exceptions', $ex->getErrors());
				$this->Session->setFlash($ex->getDetail(), 'danger');
			};
		}

		// Set crumbs
		$this->crumbs[] = [ __('Campaigns'), [ P => 'newsletter', C => 'campaigns', A => 'index' ] ];
		$this->crumbs[] = [ __('Edit campaign'), [ P => 'newsletter', C => 'campaigns', A => 'create', $id ] ];

		$this->crumbs[] = $id && $campaign ? __('Test and send campaign %s', $campaign->data['title']) : __('Create campaign');

		$this->set(compact('id', 'campaign', 'html', 'exceptions'));
	}

}
