<?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\Updates;

use Piwik\Common;
use Piwik\Config;
use Piwik\Container\StaticContainer;
use Piwik\DataAccess\ArchiveTableCreator;
use Piwik\Db;
use Piwik\DbHelper;
use Piwik\Updater;
use Piwik\Updater\Migration\Factory as MigrationFactory;
use Piwik\Updates;

class Updates_5_2_0_b2 extends Updates
{
    /**
     * @var MigrationFactory
     */
    private $migration;

    public function __construct(MigrationFactory $factory)
    {
        $this->migration = $factory;
    }

    public function getMigrations(Updater $updater)
    {
        $migrations = [];

        $config = Config::getInstance();
        $dbConfig = $config->database;

        // only run migration if config is not set
        if (empty($dbConfig['collation'])) {
            $collation = $this->detectCollationForMigration();

            if (null !== $collation) {
                $migrations[] = $this->migration->config->set(
                    'database',
                    'collation',
                    $collation
                );
            }
        }

        return $migrations;
    }

    public function doUpdate(Updater $updater)
    {
        $updater->executeMigrations(__FILE__, $this->getMigrations($updater));
    }

    private function detectCollationForMigration(): ?string
    {
        try {
            $db = Db::get();

            $metadataProvider = StaticContainer::get('Piwik\Plugins\DBStats\MySQLMetadataProvider');
            $userTableStatus = $metadataProvider->getTableStatus('user');
            if (empty($userTableStatus['Collation'] ?? null)) {
                // if there is no user table, or no collation for it, abort detection
                // this table should always exist and something must be wrong in this case
                return null;
            }

            $userTableCollation = $userTableStatus['Collation'];
            if (!is_string($userTableCollation) || !DbHelper::isValidCollation($userTableCollation)) {
                return null;
            }

            $connectionCollation = $db->fetchOne('SELECT @@collation_connection');

            if ($userTableCollation === $connectionCollation) {
                // if the connection is matching the user table
                // we should be safe to assume we have already found a config value
                return $userTableCollation;
            }

            $archiveTable = ArchiveTableCreator::getLatestArchiveTableInstalled(ArchiveTableCreator::NUMERIC_TABLE);
            if (null === $archiveTable) {
                return null;
            }

            $archiveTableStatus = $metadataProvider->getTableStatus(Common::unprefixTable($archiveTable));

            if (
                !empty($archiveTableStatus['Collation'])
                && $archiveTableStatus['Collation'] === $userTableCollation
            ) {
                // the most recent numeric archive table is matching the collation
                // of the users table, should be a good config value to choose
                return $userTableCollation;
            }
        } catch (\Exception $e) {
            // rely on the system check if detection failed
        }

        return null;
    }
}
