<?php

/*
+---------------------------------------------------------------------------+
| Revive Adserver                                                           |
| http://www.revive-adserver.com                                            |
|                                                                           |
| Copyright: See the COPYRIGHT.txt file.                                    |
| License: GPLv2 or later, see the LICENSE.txt file.                        |
+---------------------------------------------------------------------------+
*/

require_once RV_PATH . '/lib/RV.php';

require_once MAX_PATH . '/lib/max/other/common.php';
require_once LIB_PATH . '/Plugin/Component.php';
require_once MAX_PATH . '/lib/max/Plugin/Translation.php';
require_once MAX_PATH . '/lib/OA.php';
require_once MAX_PATH . '/lib/OA/Admin/DaySpan.php';
require_once MAX_PATH . '/lib/OA/Admin/Statistics/Factory.php';
require_once MAX_PATH . '/lib/OA/Permission.php';
require_once MAX_PATH . '/lib/OX/Extension/reports/ReportTrait.php';

/**
 * Error codes used by report plugins
 */
define('PLUGINS_REPORTS_MISSING_SHEETS_ERROR', 1);


/**
 * Plugins_Reports is an abstract class that defines an interface for every
 * report plugin to implement.
 *
 * @package    OpenXPlugin
 * @subpackage Reports
 */
abstract class Plugins_Reports extends OX_Component
{
    use ReportTrait;

    /**
     * The format the report is returned as (eg. "xls").
     *
     * @var string
     */
    public $_export;

    /**
     * The users authorised to run the report (eg. array(OA_ACCOUNT_ADMIN,
     * OA_ACCOUNT_MANAGER), etc).
     *
     * @var integer
     */
    public $_authorize;

    /**
     * An array containing the details required to display the
     * report's input value form in the UI.
     *
     * @var array
     */
    public $_import;

    /**
     * The common OA_Admin_DaySpan object used by all reports to
     * limit the time range of the report.
     *
     * @var OA_Admin_DaySpan
     */
    public $_oDaySpan;

    /**
     * A string representation of the start date of the report.
     *
     * @var string
     */
    public $_startDateString;

    /**
     * A string representation of the end date of the report.
     *
     * @var string
     */
    public $_endDateString;

    /**
     * A public method to call an implemented report's initInfo() method,
     * and then return the plugin's information array as generated by the
     * initInfo() method.
     *
     * @return array The array generated by the
     *               {@link Plugins_Reports::infoArray()} method.
     */
    public function info()
    {
        $this->initInfo();
        return $this->infoArray();
    }

    /**
     * An abstract method that MUST be implemented in every plugin, to set the
     * plugin's private variables with the required details about the plugin.
     */
    abstract public function initInfo();

    /**
     * An abstract method that MUST be implemented in every plugin, which must
     * return an array of the required information for laying out the plugin's
     * report generation screen/the variables required for generating the report.
     */
    abstract public function getDefaults();

    /**
     * An abstract method that MUST be implemented in every plugin, to save
     * the values used for the report by the user to the user's session
     * preferences, so that they can be re-used in other reports.
     */
    abstract public function saveDefaults();

    /**
     * An abstract method that MUST be implemented in every plugin, to execute
     * the plugin, generating the required report.
     * @return void|int - Return error code on errors
     */
    abstract public function execute();

    /**
     * Return error message for given error code
     *
     * @param int $errorCode
     * @return string
     */
    public function getErrorMessage($errorCode)
    {
        return match ($errorCode) {
            PLUGINS_REPORTS_MISSING_SHEETS_ERROR => $GLOBALS['strReportErrorMissingSheets'],
            default => $GLOBALS['strReportErrorUnknownCode'] . htmlspecialchars($errorCode),
        };
    }

    /**
     * An abstract method that MUST be implemented in every plugin, to return
     * an array of index/value strings to display as sub-headings in report
     * worksheets.
     *
     * @access private
     * @return array The array of index/value sub-headings.
     */
    abstract public function _getReportParametersForDisplay();

    /**
     * A public method to return the required information about the report plugin.
     *
     * @return array An array providing information about the report class.
     *               The details required to be set in the array are:
     *                  'plugin-name'          => The (translated) name of the plugin
     *                  'plugin-description'   => The (translated) description of the plugin
     *                  'plugin-category'      => The report category (eg. admin, advertiser,
     *                                            agency, publisher)
     *                  'plugin-category-name' => The (translated) name of the report category
     *                  'plugin-author'        => The name of the author
     *                  'plugin-export'        => The format the report is returned as
     *                  'plugin-authorize'     => The users authorised to run the report (eg. OA_ACCOUNT_ADMIN,
     *                                            OA_ACCOUNT_MANAGER, etc)
     *                  'plugin-import'        => An array containing the details required to display the
     *                                            report's input value form in the UI
     */
    public function infoArray()
    {
        $this->initInfo();
        include_once MAX_PATH . '/lib/max/Plugin/Translation.php';
        MAX_Plugin_Translation::init($this->extension, $this->group);
        $aPluginInfo = [
            "plugin-name" => MAX_Plugin_Translation::translate($this->_name, $this->extension, $this->group),
            "plugin-description" => MAX_Plugin_Translation::translate($this->_description, $this->extension, $this->group),
            'plugin-category' => $this->_category,
            'plugin-category-name' => MAX_Plugin_Translation::translate($this->_categoryName, $this->extension, $this->group),
            "plugin-author" => $this->_author,
            "plugin-export" => $this->_export,
            "plugin-authorize" => $this->_authorize,
            "plugin-import" => $this->_import,
        ];
        return $aPluginInfo;
    }

    /**
     * A method to determine if a report can be executed by a user or not.
     *
     * @return boolean True if the report is allowed to be executed by the
     *                 current user, false otherwise.
     */
    public function isAllowedToExecute()
    {
        // Backwards-compatible way of pulling authorization
        $aInfo = $this->info();
        $authorizedUserTypes = $aInfo['plugin-authorize'];
        return OA_Permission::isAccount($authorizedUserTypes);
    }

    /**
     * A private method to prepare the report range information from an
     * OA_Admin_DaySpan object.
     *
     * @access private
     * @param OA_Admin_DaySpan $oDaySpan The OA_Admin_DaySpan object to set
     *                                   the report range information from.
     */
    public function _prepareReportRange($oDaySpan)
    {
        global $date_format;
        if (!empty($oDaySpan)) {
            $this->_oDaySpan = $oDaySpan;
            $this->_startDateString = $oDaySpan->getStartDateString($date_format);
            $this->_endDateString = $oDaySpan->getEndDateString($date_format);
        } else {
            $oDaySpan = new OA_Admin_DaySpan();

            // take as the start date the date when adds were serverd
            $aConf = $GLOBALS['_MAX']['CONF'];
            $oDbh = OA_DB::singleton();
            $query = "SELECT MIN(date_time) as min_datetime FROM " . $oDbh->quoteIdentifier($aConf['table']['prefix'] . $aConf['table']['data_summary_ad_hourly'], true) . " WHERE 1=1";
            $startDate = $oDbh->queryRow($query);
            $startDate = $startDate['min_datetime'];
            $oStartDate = new Date($startDate);

            $oEndDate = new Date();
            $oDaySpan->setSpanDays($oStartDate, $oEndDate);
            $this->_oDaySpan = &$oDaySpan;
            $this->_startDateString = MAX_Plugin_Translation::translate('Beginning', $this->extension, $this->group);
            $this->_endDateString = $oDaySpan->getEndDateString($date_format);
        }

        $utcUpdate = OA_Dal_ApplicationVariables::get('utc_update');
        if (!empty($utcUpdate)) {
            $oUpdate = new Date($utcUpdate);
            $oUpdate->setTZbyID('UTC');
            // Add 12 hours
            $oUpdate->addSeconds(3600 * 12);

            $startDate = new Date($oDaySpan->oStartDate);
            $endDate = new Date($oDaySpan->oEndDate);

            if ($oUpdate->after($endDate) || $oUpdate->after($startDate)) {
                $this->_displayInaccurateStatsWarning = true;
            }
        }
    }

    /**
     * A private method to prepare the output filename for a plugin report.
     *
     * @access private
     * @return string The string name of the report.
     */
    public function _getReportFileName()
    {
        $reportFileName = '';
        $reportFileName .= MAX_Plugin_Translation::translate(html_entity_decode($this->_name, null, 'UTF-8'), $this->extension, $this->group);
        $reportFileName .= ' ';
        $reportFileName .= $GLOBALS['strFrom'];
        $reportFileName .= ' ';
        $reportFileName .= $this->_startDateString;
        $reportFileName .= ' ';
        $reportFileName .= $GLOBALS['strTo'];
        $reportFileName .= ' ';
        $reportFileName .= $this->_endDateString;
        $reportFileName .= '.';
        $reportFileName .= $this->_export;

        return $reportFileName;
    }

    /**
     * A private method to return an array containing the start and end dates
     * of a report in a format that is suitable for display in a worksheet's
     * sub-heading.
     *
     * @access private
     * @return array An array containing the Start Date and End Date, if required.
     */
    public function _getDisplayableParametersFromDaySpan()
    {
        $aParams = [];
        if (!is_null($this->_oDaySpan)) {
            global $date_format;
            $aParams[MAX_Plugin_Translation::translate('Start Date', $this->extension, $this->group)] =
                $this->_oDaySpan->getStartDateString($date_format);
            $aParams[MAX_Plugin_Translation::translate('End Date', $this->extension, $this->group)] =
                $this->_oDaySpan->getEndDateString($date_format);
        }
        return $aParams;
    }
}
