<?php

/**
 * Matomo - free/libre analytics platform
 *
 * @link    https://matomo.org
 * @license https://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
 */
declare (strict_types=1);
namespace Piwik\Plugins\BotTracking;

use Piwik\Date;
use Piwik\Piwik;
use Piwik\Plugin;
use Piwik\Plugins\BotTracking\Dao\BotRequestsDao;
use Piwik\Plugins\SitesManager\API;
use Piwik\Plugins\BotTracking\Metrics as BotMetrics;
use Piwik\Plugins\BotTracking\Reports\AIChatbotsRealTimeWidgets;
use Piwik\Tracker\Request;
/**
 * BotTracking Plugin
 *
 * Tracks AI assistant and bot interactions without creating visits.
 * Stores telemetry data in dedicated tables for analysis of bot behavior
 * and system performance.
 */
class BotTracking extends Plugin
{
    /**
     * @return bool
     */
    public function isTrackerPlugin()
    {
        return \true;
    }
    /**
     * @return array<string, string>
     */
    public function registerEvents() : array
    {
        return ['AssetManager.getStylesheetFiles' => 'getStylesheetFiles', 'PrivacyManager.deleteLogsOlderThan' => 'deleteLogsOlderThan', 'PrivacyManager.deleteDataSubjectsForDeletedSites' => 'deleteDataSubjectsForDeletedSites', 'Tracker.isBotRequest' => 'isBotRequest', 'Translate.getClientSideTranslationKeys' => 'getClientSideTranslationKeys', 'Metrics.getEvolutionUnit' => 'getEvolutionUnit', 'Metrics.getDefaultMetricTranslations' => 'addMetricTranslations', 'Metrics.getDefaultMetricDocumentationTranslations' => 'addMetricDocumentationTranslations', 'Metrics.getDefaultMetricSemanticTypes' => 'addMetricSemanticTypes', 'API.addGlossaryItems' => 'addGlossaryItems'];
    }
    /**
     * @return void
     */
    public function install()
    {
        (new BotRequestsDao())->createTable();
    }
    /**
     * @return void
     */
    public function uninstall()
    {
        (new BotRequestsDao())->dropTable();
    }
    public function deleteLogsOlderThan(Date $dateUpperLimit) : void
    {
        (new BotRequestsDao())->deleteOldRecords($dateUpperLimit);
    }
    /**
     * @param array<string, int> $result
     */
    public function deleteDataSubjectsForDeletedSites(array &$result) : void
    {
        $allExistingIdSites = API::getInstance()->getAllSitesId();
        $allExistingIdSites = array_map('intval', $allExistingIdSites);
        $maxIdSite = max($allExistingIdSites);
        if (empty($maxIdSite)) {
            return;
        }
        $dao = new BotRequestsDao();
        $idSitesInTable = $dao->getDistinctIdSitesInTable($maxIdSite);
        $idSitesNoLongerExisting = array_diff($idSitesInTable, $allExistingIdSites);
        if (count($idSitesNoLongerExisting) > 0) {
            $result[$dao::getTableName()] = $dao->deleteRecordsForIdSites($idSitesNoLongerExisting);
        }
    }
    /**
     * @todo Remove, once Device Detector is able to detect all known ai bots
     */
    public function isBotRequest(bool &$isBot, Request $request) : void
    {
        $botDetector = new \Piwik\Plugins\BotTracking\BotDetector($request->getUserAgent());
        if ($botDetector->isBot()) {
            $isBot = \true;
        }
    }
    public function getEvolutionUnit(?string &$unit, string $column) : void
    {
        if ($column === \Piwik\Plugins\BotTracking\Metrics::METRIC_AI_CHATBOTS_CLICK_THROUGH_RATE) {
            $unit = '%';
        }
    }
    /**
     * @param array<string, string> $translations
     */
    public function addMetricTranslations(array &$translations) : void
    {
        $translations = array_merge($translations, BotMetrics::getMetricTranslations());
        // Register a default name for the generic 'requests' column used by the new content-URL
        // reports. Without this the Glossary majority heuristic renders name = null for the
        // 'requests' metric because three reports expose it under different per-report scoped
        // documentation strings, leaving no single translation with a majority. Registering the
        // default here mirrors the documentation registration in addMetricDocumentationTranslations.
        if (!isset($translations[\Piwik\Plugins\BotTracking\Metrics::COLUMN_REQUESTS])) {
            $translations[\Piwik\Plugins\BotTracking\Metrics::COLUMN_REQUESTS] = Piwik::translate('BotTracking_ColumnRequests');
        }
    }
    /**
     * @param array<string, string> $translations
     */
    public function addMetricDocumentationTranslations(array &$translations) : void
    {
        $translations = array_merge($translations, BotMetrics::getMetricDocumentation());
        // Register a default documentation for the generic 'requests' column used by the
        // new content-URL reports. Without this default the Glossary majority heuristic
        // (array_sum - max < max) would not pick a winner because the three reports that
        // expose 'requests' each use a different documentation string (generic, page-scoped,
        // document-scoped), leaving no single value with a majority. Setting a default here
        // ensures the metric always appears in the glossary with the generic tooltip.
        if (!isset($translations[\Piwik\Plugins\BotTracking\Metrics::COLUMN_REQUESTS])) {
            $translations[\Piwik\Plugins\BotTracking\Metrics::COLUMN_REQUESTS] = Piwik::translate('BotTracking_ColumnRequestsDocumentation');
        }
    }
    /**
     * @param array<string|int, string> $types
     */
    public function addMetricSemanticTypes(array &$types) : void
    {
        $types = array_merge($types, BotMetrics::getMetricSemanticTypes());
    }
    /**
     * @param array<string, array{title: string, entries: array<int, array<string, string>>}> $glossaryItems
     */
    public function addGlossaryItems(array &$glossaryItems) : void
    {
        Piwik::checkUserHasSomeViewAccess();
        $category = Piwik::translate('General_AIAssistants');
        foreach (AIChatbotsRealTimeWidgets::getAllWidgets() as $widget) {
            $glossaryItems['reports']['entries'][] = ['name' => sprintf('%s (%s)', Piwik::translate($widget['name']), $category), 'documentation' => Piwik::translate($widget['documentation'])];
        }
    }
    /**
     * @param string[] $translationKeys
     * @return void
     */
    public function getClientSideTranslationKeys(&$translationKeys)
    {
        $translationKeys[] = 'BotTracking_DetectingYourSite';
        $translationKeys[] = 'BotTracking_SiteWithoutDataBackToMatomo';
        $translationKeys[] = 'BotTracking_SiteWithoutDataChooseTrackingMethod';
        $translationKeys[] = 'BotTracking_SiteWithoutDataChooseTrackingMethodPreamble1';
        $translationKeys[] = 'BotTracking_SiteWithoutDataChooseTrackingMethodPreamble2';
        $translationKeys[] = 'BotTracking_SiteWithoutDataInstallWithX';
        $translationKeys[] = 'BotTracking_SiteWithoutDataNotYetReady';
        $translationKeys[] = 'BotTracking_SiteWithoutDataOtherInstallMethods';
        $translationKeys[] = 'BotTracking_SiteWithoutDataOtherInstallMethodsIntro';
        $translationKeys[] = 'BotTracking_SiteWithoutDataInstallWithXRecommendation';
        $translationKeys[] = 'BotTracking_SiteWithoutDataRecommendationText';
        $translationKeys[] = 'General_ErrorRequest';
        $translationKeys[] = 'General_Refresh';
        $translationKeys[] = 'Mobile_NavigationBack';
        $translationKeys[] = 'BotTracking_NoRecentAIBotRequests';
    }
    /**
     * @param string[] $stylesheets
     * @return void
     */
    public function getStylesheetFiles(&$stylesheets)
    {
        $stylesheets[] = "plugins/BotTracking/stylesheets/BotTracking.less";
    }
}
