<?php

// TODO: [notImportant] calculate time split by phases + raportat la final

namespace App\Reports\Sources;

abstract class ProgressManagerAbstract
{

	/**
	 * The report generation id - may not be set if we do not want to actually write the progress in the DB.
	 * @var int
	 */
	protected ?int $idReportGeneration = null;

	/**
	 * The specific phases and steps for the current report source.
	 * @var array
	 */
	protected array $specificPhasesAndStepsCfg;

	/**
	 * The extra phases and steps involved with the report generation.
	 * @var array
	 */
	protected array $extraPhasesAndStepsCfg = [
		'preCustomFilters'=>[
			'applyPreCustomFilters'=>100,
		],
		'processingRecords' => [
			'loopResults' => 100,
		],
		'postCustomFilters'=>[
			'applyPostCustomFilters'=>100,
		],
		'writeReport' => [
			'indexingColumns'=>7,
			'initialize'=>3,
			'writeFile'=>90,
		],
		'pivotTables' => [
			'generatingPivots'=>100,
		],
		'extraOptions' => [
			'sendReportsByEmail'=>100,
		],
	];

	/**
	 * The unix timestamp of the last update - this is used for making sure that at least 1-2 seconds
	 * pass between updates.
	 * @var integer
	 */
	protected int $lastTouch = 0;

	/**
	 * Stores the report generation id - the field is optional.
	 */
	public function __construct(?int $idReportGeneration=null)
	{
		// check that the specific phases and steps are defined.
		if (!$this->specificPhasesAndStepsCfg) {
			throw new \Exception("Phases and steps were not defined for  ".get_called_class());
		}

		if ($idReportGeneration===null) {
			return ;
		}

		if ($idReportGeneration<=0) {
			throw new \Exception("Invalid report generation id `{$idReportGeneration}` on ".__METHOD__);
		}

		$this->idReportGeneration = $idReportGeneration;

	}


	/**
	 * Returns the report source based on the current class namespace.
	 * @return string
	 */
	public function getReportSource()
	{
		$ns = getClassNamespace(get_called_class());
		return substr($ns, strrpos($ns, '\\')+1);
	}

	/**
	 * Returns the report generation id (or null if not set).
	 * @return int|NULL
	 */
	public function getIdReportGeneration() :?int
	{
		return $this->idReportGeneration;
	}

	/**
	 * Returns all phases and steps for the current report source.
	 */
	protected function getAllPhasesAndSteps() :array
	{
		return array_merge($this->specificPhasesAndStepsCfg, $this->extraPhasesAndStepsCfg);
	}

	/**
	 * Store the current phase/step/percent.
	 * @param string $phase
	 * @param string $step
	 * @param float $stepPercent
	 */
	public function setStatus(string $phase, string $step, float $stepPercent) :void
	{

		// CHECK INPUT ----------------------------------------------------------------------------
		if ($stepPercent<0 or $stepPercent>100) {
			throw new \Exception('Invalid value for `stepPercent` param on '.__METHOD__);
		}

		$allPas = $this->getAllPhasesAndSteps();

		if (!key_exists($phase, $allPas)) {
			throw new \Exception("Invalid phase `{$phase}` called in ".get_called_class());
		}

		if (!key_exists($step, $allPas[$phase])) {
			throw new \Exception("Invalid step `{$step}` on phase `{$phase}` called in ".get_called_class());
		}

		// if no idReportGeneration - simply skip the storage of phase/step/percent
		if (!$this->idReportGeneration) {
			return ;
		}

		// do not make too many updates in the DB (once every 3s)
		$currentTime = time();
		if ($this->lastTouch and ($currentTime-$this->lastTouch)<=2) {
			return ;
		}

		// store the last touch of the progress on the current generation
		$this->lastTouch = $currentTime;

		// update the progress status in the DB
		$reportGenProgress = \Entity\ReportGeneration::updateProgress($this->idReportGeneration);
		$reportGenProgress->phase = $phase;
		$reportGenProgress->step = $step;
		$reportGenProgress->stepPercent = $stepPercent;
		$reportGenProgress->save();

	}


	/**
	 * Returns the progress details for the given phase and step.
	 * Returns an array containing phase/step bar percents and names.
	 * @param string $phaseCode
	 * @param string $stepCode
	 * @param float $stepPercent
	 * @return array
	 */
	public function getProgressDetails(string $phaseCode, string $stepCode, float $stepPercent): array
	{

/* // TODO: [reactivateProgressManagerPercents] - uncomment this; we should use this when we finish refactoring of reports gen
		// validate stepPercent
		if (!$stepPercent<0 or $stepPercent>100) {
			throw new \App\Reports\Sources\Exception("The step percent `{$stepPercent}` for the report source `{$reportSource}` must be between 0 and 100.");
		}

		// determine the progress percents
		$allPhasesAndSteps = $this->getAllPhasesAndSteps();

		// check if the phase exists
		if (!key_exists($phaseCode, $allPhasesAndSteps)) {
			throw new \App\Reports\Sources\Exception("Phase `{$phaseCode}` not found in the report source `{$reportSource}`.");
		}

		// check if the step exists
		if (!key_exists($stepCode, $allPhasesAndSteps[$phaseCode])) {
			throw new \App\Reports\Sources\Exception("The step code `{$stepCode}` not found for phase `{$phaseCode}` in the report source `{$reportSource}`.");
		}

		$phaseIndex = array_search($phaseCode, array_keys($allPhasesAndSteps));

		$stepsList = $allPhasesAndSteps[$phaseCode];

		$phaseStepsTotalSize = array_sum($stepsList);

		$stepSize = 0;
		foreach($stepsList as $currStep=>$currStepSize) {
			if ($currStep==$stepCode) {
				$stepSize += $currStepSize * $stepPercent / 100;
				break;
			} else {
				$stepSize += $currStepSize;
			}
		}

		// calculate the bar percents
		$barStepPercent = $stepSize / $phaseStepsTotalSize;
		$barPhasePercent = ($phaseIndex + $barStepPercent) / count($allPhasesAndSteps);
*/
		// load lang files
		\App\Loader_Lang::getInstance()->loadAppFile("_customLoad/reports/generalData.lang.php");
		$reportSource = $this->getReportSource();
		$source = lcfirst($reportSource);
		\App\Loader_Lang::getInstance()->loadAppFile("_customLoad/reports/{$source}/phasesAndSteps.lang.php");
		$_LANG = \App\Loader_Lang::getInstance()->getAll();

		// inject all returned data
		$return = [
			'phaseName' => $_LANG['reports']['phasesAndSteps']['general']['phases'][$phaseCode] ? : $_LANG['reports']['phasesAndSteps'][$source]['phaseName'][$phaseCode] ? : $phaseCode,
			'stepName' => $_LANG['reports']['phasesAndSteps']['general']['steps'][$phaseCode][$stepCode] ? : $_LANG['reports']['phasesAndSteps'][$source]['stepName'][$phaseCode][$stepCode] ? : $stepCode,
//			'mainPercent' => round($barStepPercent * 100, 2),
//			'phasePercent' => round($barPhasePercent * 100, 2),
		]; // TODO: [reactivateProgressManagerPercents] - uncomment this; we should use this when we finish refactoring of reports gen

		return $return;

	}


}

