<?php

/**
 * Matomo - free/libre analytics platform
 *
 * @link    https://matomo.org
 * @license https://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
 */

namespace Piwik\Plugins\Goals\Reports;

use Piwik\API\Request;
use Piwik\Common;
use Piwik\DataTable;
use Piwik\DataTable\Filter\CalculateEvolutionFilter;
use Piwik\Metrics;
use Piwik\Metrics\Formatter as MetricFormatter;
use Piwik\NumberFormatter;
use Piwik\Period\Month;
use Piwik\Period\Range;
use Piwik\Piwik;
use Piwik\Period\Factory as PeriodFactory;
use Piwik\Plugin;
use Piwik\Plugin\ViewDataTable;
use Piwik\Plugins\CoreHome\Columns\Metrics\ConversionRate;
use Piwik\Plugins\CoreVisualizations\Visualizations\JqplotGraph\Evolution;
use Piwik\Plugins\CoreVisualizations\Visualizations\Sparklines;
use Piwik\Plugins\Goals\Goals;
use Piwik\Plugins\Goals\Pages;
use Piwik\Report\ReportWidgetFactory;
use Piwik\Site;
use Piwik\Tracker\GoalManager;
use Piwik\Url;
use Piwik\Widget\WidgetsList;

class Get extends Base
{
    protected function init()
    {
        parent::init();

        $this->name = Piwik::translate('Goals_Goals');
        $this->processedMetrics = ['conversion_rate'];
        $this->documentation = Piwik::translate('Goals_OverviewReportDocumentation');
        $this->order = 1;
        $this->orderGoal = 50;
        $this->metrics = ['nb_conversions', 'nb_visits_converted', 'revenue'];
        $this->parameters = null;
    }

    private function getGoals()
    {
        $idSite = $this->getIdSite();
        $goals = Request::processRequest('Goals.getGoals', ['idSite' => $idSite, 'filter_limit' => '-1'], $default = []);
        return $goals;
    }

    private function getGoal($goalId)
    {
        $goals = $this->getGoals();

        if (!empty($goals[$goalId])) {
            return $goals[$goalId];
        }
    }

    public function configureWidgets(WidgetsList $widgetsList, ReportWidgetFactory $factory)
    {
        $idSite  = Common::getRequestVar('idSite', 0, 'int');

        if (empty($idSite)) {
            return;
        }

        $goals   = $this->getGoals();
        $reports = Goals::getReportsWithGoalMetrics();

        $page = new Pages($factory, $reports);

        $widgetsList->addWidgetConfigs($page->createGoalsOverviewPage($goals));

        if ($this->isEcommerceEnabled($idSite)) {
            $widgetsList->addWidgetConfigs($page->createEcommerceOverviewPage());
            $widgetsList->addWidgetConfigs($page->createEcommerceSalesPage());
        }

        foreach ($goals as $goal) {
            $widgetsList->addWidgetConfigs($page->createGoalDetailPage($goal));
        }
    }

    private function getIdSite()
    {
        return Common::getRequestVar('idSite', null, 'int');
    }

    private function isEcommerceEnabled($idSite)
    {
        if (!Plugin\Manager::getInstance()->isPluginActivated('Ecommerce')) {
            return false;
        }

        $site = new Site($idSite);
        return $site->isEcommerceEnabled();
    }

    private function hasGoalRevenue(string $idGoal): bool
    {
        $params = ['format_metrics' => '0'];
        if (!empty($idGoal)) {
            $params['idGoal'] = $idGoal;
        }

        $datatable = Request::processRequest('Goals.get', $params);

        if (!($datatable instanceof DataTable)) {
            return false;
        }

        $row = $datatable->getFirstRow();
        return $row && (float) $row->getColumn('revenue') > 0;
    }

    public function configureView(ViewDataTable $view)
    {
        $idGoal = Common::getRequestVar('idGoal', 0, 'string');

        $idSite = $this->getIdSite();

        if ($view->isViewDataTableId(Sparklines::ID)) {
            /** @var Sparklines $view */
            $isEcommerceEnabled = $this->isEcommerceEnabled($idSite);

            $onlySummary = Common::getRequestVar('only_summary', 0, 'int');

            if ($onlySummary && !empty($idGoal)) {
                if (is_numeric($idGoal)) {
                    $view->config->title_attributes = ['goal-page-link' => $idGoal];
                }

                // in Goals overview summary we show proper title for a goal
                $goal = $this->getGoal($idGoal);
                if (!empty($goal['name'])) {
                    $view->config->title = Piwik::translate('Goals_GoalX', "'" . $goal['name'] . "'");
                }
            } else {
                $view->config->title = '';
            }

            $view->config->addTranslations([
                'nb_visits' => Piwik::translate('VisitsSummary_NbVisitsDescription'),
                'nb_conversions' => Piwik::translate('Goals_ConversionsDescription'),
                'nb_visits_converted' => Piwik::translate('General_NVisits'),
                'conversion_rate' => Piwik::translate('Goals_OverallConversionRate'),
                'revenue' => Piwik::translate('Goals_OverallRevenue'),
            ]);

            // Adding conversion rate as extra processed metrics ensures it will be formatted
            // This is not done when comparing, as comparison does its own formatting
            if (!$view->isComparing()) {
                $view->config->filters[] = function (DataTable $t) {
                    $extraProcessedMetrics = $t->getMetadata(DataTable::EXTRA_PROCESSED_METRICS_METADATA_NAME);

                    if (empty($extraProcessedMetrics)) {
                        $extraProcessedMetrics = [];
                    }
                    $extraProcessedMetrics[] = new ConversionRate();
                    $t->setMetadata(DataTable::EXTRA_PROCESSED_METRICS_METADATA_NAME, $extraProcessedMetrics);
                };
            }

            $allowMultiple = Common::getRequestVar('allow_multiple', 0, 'int');

            if ($allowMultiple) {
                $view->config->addSparklineMetric(['nb_conversions', 'nb_visits_converted'], $order = 10);
            } else {
                $view->config->addSparklineMetric(['nb_conversions'], $order = 10);
            }

            $view->config->addSparklineMetric(['conversion_rate'], $order = 20);

            if (empty($idGoal)) {
                // goals overview sparklines below evolution graph

                if ($isEcommerceEnabled || $this->hasGoalRevenue($idGoal)) {
                    // this would be ideally done in Ecommerce plugin but then it is hard to keep same order
                    $view->config->addSparklineMetric(['revenue'], $order = 30);
                }
            } else {
                if ($onlySummary) {
                    // in Goals Overview we list an overview for each goal....
                    $view->config->addTranslation('conversion_rate', Piwik::translate('Goals_ConversionRate'));
                }

                if ($isEcommerceEnabled || $this->hasGoalRevenue($idGoal)) {
                    // in Goals detail page and per-goal summary on Goals Overview
                    $view->config->addSparklineMetric(['revenue'], $order = 30);
                }
            }

            // Add evolution values to sparklines
            [$lastPeriodDate, $ignore] = Range::getLastDate();
            if ($lastPeriodDate !== false) {
                // Using a filter here ensures the additional request is only performed when the view is rendered
                $view->config->filters[] = function ($datatable) use ($view, $lastPeriodDate, $idSite) {
                    /** @var DataTable $previousData */
                    $previousData    = Request::processRequest(
                        'Goals.get',
                        ['date' => $lastPeriodDate, 'format_metrics' => '0']
                    );
                    $previousDataRow = $previousData->getFirstRow();

                    $currentPeriod     = PeriodFactory::build(Piwik::getPeriod(), Common::getRequestVar('date'));
                    $currentPrettyDate = ($currentPeriod instanceof Month ? $currentPeriod->getLocalizedLongString(
                    ) : $currentPeriod->getPrettyString());
                    $lastPeriod        = PeriodFactory::build(Piwik::getPeriod(), $lastPeriodDate);
                    $lastPrettyDate    = ($currentPeriod instanceof Month ? $lastPeriod->getLocalizedLongString(
                    ) : $lastPeriod->getPrettyString());
                    $metricTranslations = $view->config->translations;

                    $view->config->compute_evolution = function (
                        $columns,
                        $metrics
                    ) use (
                        $currentPrettyDate,
                        $lastPrettyDate,
                        $previousDataRow,
                        $idSite,
                        $metricTranslations
                    ) {
                        $value      = reset($columns);
                        $columnName = key($columns);
                        $pastValue  = $previousDataRow ? $previousDataRow->getColumn($columnName) : 0;

                        if (!is_numeric($value)) {
                            return;
                        }

                        // Format
                        $formatter             = new MetricFormatter();
                        $currentValueFormatted = $value;
                        $pastValueFormatted    = $pastValue;
                        if (strpos($columnName, 'revenue') !== false) {
                            $currencySymbol        = Site::getCurrencySymbolFor($idSite);
                            $pastValueFormatted    = NumberFormatter::getInstance()->formatCurrency(
                                $pastValue,
                                $currencySymbol,
                                GoalManager::REVENUE_PRECISION
                            );
                            $currentValueFormatted = NumberFormatter::getInstance()->formatCurrency(
                                $value,
                                $currencySymbol,
                                GoalManager::REVENUE_PRECISION
                            );
                        } else {
                            foreach ($metrics as $metric) {
                                if ($metric->getName() === $columnName) {
                                    $pastValueFormatted    = $metric->format($pastValue, $formatter);
                                    $currentValueFormatted = $metric->format($value, $formatter);
                                    break;
                                }
                            }
                        }

                        $columnTranslation = $metricTranslations[$columnName] ?? '';
                        if ($columnTranslation === '') {
                            $columnTranslations = Metrics::getDefaultMetricTranslations();
                            if (array_key_exists($columnName, $columnTranslations)) {
                                $columnTranslation = $columnTranslations[$columnName];
                            }
                        }

                        return [
                            'currentValue' => $value,
                            'pastValue'    => $pastValue,
                            'isLowerValueBetter' => Metrics::isLowerValueBetter($columnName),
                            'tooltip'      => Piwik::translate('General_EvolutionSummaryGeneric', [
                                $currentValueFormatted . ' ' . $columnTranslation,
                                $currentPrettyDate,
                                $pastValueFormatted . ' ' . $columnTranslation,
                                $lastPrettyDate,
                                CalculateEvolutionFilter::calculate($value, $pastValue, $precision = 1),
                            ]),
                        ];
                    };
                };
            }
        } elseif ($view->isViewDataTableId(Evolution::ID)) {
            if (!empty($idSite) && Piwik::isUserHasWriteAccess($idSite) && $idGoal > GoalManager::IDGOAL_ORDER) {
                $view->config->title_edit_entity_url = 'index.php' . Url::getCurrentQueryStringWithParametersModified([
                    'module' => 'Goals',
                    'action' => 'manage',
                    'forceView' => null,
                    'viewDataTable' => null,
                    'showtitle' => null,
                    'random' => null,
                    'format_metrics' => 0,
                ]);
            }

            $goal = $this->getGoal($idGoal);
            if (!empty($goal['name'])) {
                $view->config->title = Piwik::translate('Goals_GoalX', "'" . $goal['name'] . "'");
                if (!empty($goal['description'])) {
                    $view->config->description = $goal['description'];
                }
            } else {
                $view->config->title = Piwik::translate('General_EvolutionOverPeriod');
            }

            if (empty($view->config->columns_to_display)) {
                $view->config->columns_to_display = ['nb_conversions'];
            }
        }
    }

    public function configureReportMetadata(&$availableReports, $infos)
    {
        if (!$this->isEnabled()) {
            return;
        }

        parent::configureReportMetadata($availableReports, $infos);

        $this->addReportMetadataForEachGoal($availableReports, $infos, function ($goal) {
            return Piwik::translate('Goals_GoalX', $goal['name']);
        }, $isSummary = true);
    }
}
