<?php

namespace XF\Job;

use XF\Diff3;
use XF\Entity\Template;
use XF\Repository\TemplateHistoryRepository;

use function count;

class TemplateMerge extends AbstractJob
{
	protected $defaultData = [
		'templateIds' => [],
		'success' => [],
		'skipped' => [],
		'count' => 0,
		'total' => null,
	];

	public function run($maxRunTime)
	{
		$start = microtime(true);
		$templateIds = $this->data['templateIds'];

		if ($this->data['total'] === null)
		{
			$this->data['total'] = count($templateIds);
		}

		if (!$templateIds)
		{
			return $this->complete();
		}

		foreach ($templateIds AS $key => $templateId)
		{
			$merged = $this->mergeTemplate($templateId);
			if ($merged)
			{
				$this->data['success'][] = $templateId;
			}
			else
			{
				$this->data['skipped'][] = $templateId;
			}

			$this->data['count']++;
			unset($templateIds[$key]);

			if (microtime(true) - $start >= $maxRunTime)
			{
				break;
			}
		}

		if (!$templateIds)
		{
			return $this->complete();
		}

		$this->data['templateIds'] = $templateIds;
		return $this->resume();
	}

	protected function mergeTemplate($templateId)
	{
		$em = $this->app->em();

		/** @var Template $template */
		$template = $em->find(Template::class, $templateId, 'Style');
		if (!$template || !$template->style_id)
		{
			return false;
		}

		$parentTemplate = $template->ParentTemplate;
		if (!$parentTemplate)
		{
			return false;
		}

		if (!$parentTemplate->last_edit_date || $parentTemplate->last_edit_date < $template->last_edit_date)
		{
			return false;
		}

		/** @var TemplateHistoryRepository $historyRepo */
		$historyRepo = $em->getRepository(TemplateHistoryRepository::class);
		$previousVersion = $historyRepo->getHistoryForMerge($template, $parentTemplate);
		if (!$previousVersion)
		{
			return false;
		}

		$diff = new Diff3();

		$final = $diff->mergeToFinal(
			$template->template,
			$previousVersion->template,
			$parentTemplate->template
		);
		if ($final === false)
		{
			return false;
		}

		$template->template = $final;
		$template->last_edit_date = \XF::$time;

		// even if the template isn't changed we should
		// make the custom template the same version so
		// it is no longer outdated.
		if (!$template->isChanged('template'))
		{
			$template->updateVersionId();
		}

		return $template->save();
	}

	public function getStatusMessage()
	{
		$actionPhrase = \XF::phrase('merging');
		$typePhrase = \XF::phrase('templates');
		$total = $this->data['total'];
		if ($total)
		{
			return sprintf('%s... %s (%d/%d)', $actionPhrase, $typePhrase, $this->data['count'], $total);
		}
		else
		{
			return sprintf('%s... %s (%d)', $actionPhrase, $typePhrase, $this->data['count']);
		}
	}

	public function canCancel()
	{
		return false;
	}

	public function canTriggerByChoice()
	{
		return false;
	}
}
