<?php
namespace JExtstore\Component\JRealtimeAnalytics\Administrator\Model;
/**
 *
 * @package JREALTIMEANALYTICS::OVERVIEW::administrator::components::com_jrealtimeanalytics
 * @subpackage models
 * @author Joomla! Extensions Store
 * @copyright (C) 2014 - Joomla! Extensions Store
 * @license GNU/GPLv2 http://www.gnu.org/licenses/gpl-2.0.html
 */
defined ( '_JEXEC' ) or die ( 'Restricted access' );
use Joomla\CMS\Language\Text;
use Joomla\CMS\Date\Date;
use Joomla\CMS\HTML\HTMLHelper;
use JExtstore\Component\JRealtimeAnalytics\Administrator\Framework\Model as JRealtimeModel;
use JExtstore\Component\JRealtimeAnalytics\Administrator\Framework\Exception as JRealtimeException;

/**
 * Sources model concrete implementation <<testable_behavior>>
 *
 * @package JREALTIMEANALYTICS::OVERVIEW::administrator::components::com_jrealtimeanalytics
 * @subpackage models
 * @since 2.4
 */
class OverlookModel extends JRealtimeModel {
	/**
	 * Build list entities query
	 *
	 * @access protected
	 * @param string $previousDate
	 * @param string $currentDate
	 * @param boolean $byMonth Grouping type for additional stat
	 * @return string
	 */
	protected function buildListQuery($previousDate, $currentDate, $byMonth = false) {
		// is this a query request by month?
		$numVisits = null;
		if(!$byMonth) {
			$numVisits = ",\n COUNT(DISTINCT(" . $this->dbInstance->quoteName('session_id_person') . ")) AS numvisits" ;
		}
		
		// Fetch data from DB if not injected and filter by MySql period with SUM
		$query = "SELECT COUNT(*) AS numpages" .
				 $numVisits .
				 "\n FROM #__realtimeanalytics_serverstats" .
				 "\n WHERE " . $this->dbInstance->quoteName('visit_timestamp') .
				 "\n BETWEEN " . $this->dbInstance->quote($previousDate) .
				 "\n AND "  . $this->dbInstance->quote($currentDate);
		return $query;
	}
	
	/**
	 * Process rawdata -> processeddata
	 *
	 * @access public
	 * @return array
	 */
	public function getData(): array {
		// Initialization
		$processedData = array();
		
		// Set interval for DatePeriod
		$interval = 'R11/' . $this->getState ('statsYear') . '-02-01T00:00:00Z/P1M';
		
		if (method_exists(\DatePeriod::class, 'createFromISO8601String')) {
			// PHP 8.3+
			$periods = \DatePeriod::createFromISO8601String($interval);
		} else {
			// PHP < 8.3
			$periods = new \DatePeriod($interval);
		}
	
		// Set start date
		$currentInitialDate = new \DateTime($this->getState ('statsYear') . '-01-01', new \DateTimeZone('UTC'));
		$currentDate = $currentInitialDate->format('U');
	
		foreach ($periods as $monthIndex=>$period) {
			// Store for post processing
			$previousDate = $currentDate;
			$currentDate = strtotime($period->format('Y-m-d'));

			// Fetch data from DB if not injected and filter by MySql period with SUM
			$query = $this->buildListQuery($previousDate, $currentDate, true);
			try {
				// Step 1: load stats for the number of pages viewed
				$this->dbInstance->setQuery($query);
				$chunk = $this->dbInstance->loadRow();
				// Initialize unique visitors count
				$chunk[1] = 0;

				// Step 2: retrieve and sum up the number of unique visitors using the classic 'daily metric'
				$tempMonth = $monthIndex + 1;
				$finalStringMonth = $tempMonth < 10 ? '0' . $tempMonth : $tempMonth;
				// Call the same function with an explicit month
				$processedDataNumVisitsByDay = $this->getDataByMonth($finalStringMonth);
				foreach ($processedDataNumVisitsByDay as $numVisitsByDay) {
					$chunk[1] += $numVisitsByDay[1];
				}
				
				// Assign to processed data array
				$monthDateObject = new Date($previousDate + 86400);
				$orderMonthIndex = $monthDateObject->format('F', true, true);
				$processedData[$orderMonthIndex] = $chunk;
			} catch ( JRealtimeException $e ) {
				$this->app->enqueueMessage ( $e->getMessage (), $e->getExceptionLevel () );
				$result = array ();
				break;
			} catch ( \Exception $e ) {
				$jRealtimeException = new JRealtimeException ( $e->getMessage (), 'error' );
				$this->app->enqueueMessage ( $jRealtimeException->getMessage (), $jRealtimeException->getExceptionLevel () );
				$result = array ();
				break;
			}
				
		}
	
		// No errors detected during processing
		return $processedData;
	}
	
	/**
	 * Process rawdata -> processeddata
	 *
	 * @access public
	 * @param int $monthProcessed
	 * @return array
	 */
	public function getDataByMonth($monthProcessed = null) {
		// Initialization
		$processedData = array();
		$processedMonth = $monthProcessed ? $monthProcessed : $this->getState ('statsMonth');

		// Get the number of days in a month accordingly as repetitions -1
		if (function_exists ( 'cal_days_in_month' )) {
			$repetitions = cal_days_in_month(CAL_GREGORIAN, $processedMonth, $this->getState ('statsYear')) - 1;
		} else {
			$year = $this->getState ('statsYear');
			$repetitions = date ( 't', strtotime ( "$year-$processedMonth-01" ) ) - 1;
		}

		// Set interval for DatePeriod
		$interval = 'R' . $repetitions . '/' . $this->getState ('statsYear') . '-' . $processedMonth . '-02T00:00:00Z/P1D';

		if (method_exists(\DatePeriod::class, 'createFromISO8601String')) {
			// PHP 8.3+
			$periods = \DatePeriod::createFromISO8601String($interval);
		} else {
			// PHP < 8.3
			$periods = new \DatePeriod($interval);
		}
		
		// Set start date
		$currentInitialDate = new \DateTime($this->getState ('statsYear') . '-' . $processedMonth . '-01T00:00:00');
		$currentDate = strtotime($currentInitialDate->format('Y-m-d'));

		foreach ($periods as $day=>$period) {
			// Store for post processing
			$previousDate = $currentDate;
			$currentDate = strtotime($period->format('Y-m-d'));

			// Fetch data from DB if not injected and filter by MySql period with SUM
			$query = $this->buildListQuery($previousDate, $currentDate);
			try {
				$this->dbInstance->setQuery($query);
				$chunk = $this->dbInstance->loadRow();
					
				// Assign to processed data array
				$processedData[$day+1] = $chunk;
			} catch ( JRealtimeException $e ) {
				$this->app->enqueueMessage ( $e->getMessage (), $e->getExceptionLevel () );
				$result = array ();
				break;
			} catch ( \Exception $e ) {
				$jRealtimeException = new JRealtimeException ( $e->getMessage (), 'error' );
				$this->app->enqueueMessage ( $jRealtimeException->getMessage (), $jRealtimeException->getExceptionLevel () );
				$result = array ();
				break;
			}

		}

		// No errors detected during processing
		return $processedData;
	}
	
	/**
	 * Return select lists used as filter for editEntity
	 *
	 * @access public
	 * @param Object $record
	 * @return array
	 */
	public function getLists($record = null): array {
		$lists = [];
	
		// Supported graph theme
		$themes = [];
		$themes[] = HTMLHelper::_('select.option', 'Universal', 'Universal');
		$themes[] = HTMLHelper::_('select.option', 'Aqua', 'Aqua');
		$themes[] = HTMLHelper::_('select.option', 'Orange', 'Orange');
		$themes[] = HTMLHelper::_('select.option', 'Pastel', 'Pastel');
		$themes[] = HTMLHelper::_('select.option', 'Rose', 'Rose');
		$themes[] = HTMLHelper::_('select.option', 'Softy', 'Softy');
		$themes[] = HTMLHelper::_('select.option', 'Vivid', 'Vivid');
	
		$lists ['graphTheme'] = HTMLHelper::_ ( 'select.genericlist', $themes, 'graphtheme', 'onchange="Joomla.submitform();"', 'value', 'text', $this->getState('graphTheme', 'Universal'));
	
		// Supported graph theme
		$types = [];
		$types[] = HTMLHelper::_('select.option', 'Bars', Text::_('COM_JREALTIME_BARS_GRAPH'));
		$types[] = HTMLHelper::_('select.option', 'Lines', Text::_('COM_JREALTIME_LINES_GRAPH'));
		$lists ['graphType'] = HTMLHelper::_ ( 'select.genericlist', $types, 'graphtype', 'onchange="Joomla.submitform();"', 'value', 'text', $this->getState('graphType', 'Bars'));
		
		// Year select list
		$lists ['statsYear'] = HTMLHelper::_('select.integerlist', 2012, 2038, 1, 'stats_year', 'onchange="Joomla.submitform();"', $this->getState('statsYear', date('Y')));
		
		// Month select list
		// Supported graph theme
		$months = [];
		$months[] = HTMLHelper::_('select.option', '', Text::_('COM_JREALTIME_ALLMONTHS'));
		$months[] = HTMLHelper::_('select.option', '01', date('F', mktime(0, 0, 0, 1)));
		$months[] = HTMLHelper::_('select.option', '02', date('F', mktime(0, 0, 0, 2)));
		$months[] = HTMLHelper::_('select.option', '03', date('F', mktime(0, 0, 0, 3)));
		$months[] = HTMLHelper::_('select.option', '04', date('F', mktime(0, 0, 0, 4)));
		$months[] = HTMLHelper::_('select.option', '05', date('F', mktime(0, 0, 0, 5)));
		$months[] = HTMLHelper::_('select.option', '06', date('F', mktime(0, 0, 0, 6)));
		$months[] = HTMLHelper::_('select.option', '07', date('F', mktime(0, 0, 0, 7)));
		$months[] = HTMLHelper::_('select.option', '08', date('F', mktime(0, 0, 0, 8)));
		$months[] = HTMLHelper::_('select.option', '09', date('F', mktime(0, 0, 0, 9)));
		$months[] = HTMLHelper::_('select.option', '10', date('F', mktime(0, 0, 0, 10)));
		$months[] = HTMLHelper::_('select.option', '11', date('F', mktime(0, 0, 0, 11)));
		$months[] = HTMLHelper::_('select.option', '12', date('F', mktime(0, 0, 0, 12)));
		$lists ['statsMonth'] = HTMLHelper::_('select.genericlist', $months, 'stats_month', 'onchange="Joomla.submitform();"', 'value', 'text', $this->getState('statsMonth', ''));
		
		return $lists;
	}
	
	/**
	 * Return select lists used as filter for listEntities
	 *
	 * @access public
	 * @return array
	 */
	public function getFilters(): array {
		$filters = [];
		return $filters;
	}
}