<?php

use idoit\Module\Cmdb\Model\Ci\Table\Config;
use idoit\Module\Cmdb\Model\Ci\Table\Property;
use Symfony\Component\Filesystem\Filesystem;

global $g_comp_database;
global $g_comp_database_system;

// @see ID-10384
$migrationIdentifier = 'migrate-table-configurations';

// Check whether migration was executed before
if ($this->is_migration_done($migrationIdentifier)) {
    $g_migration_log[] = '<span class="bold">Table configuration is already migrated!</span>';
} else {
    $g_migration_log[] = '<span class="bold">Migrate table configurations...</span>';

    $daoTenant = new \isys_cmdb_dao($g_comp_database);
    $daoSystem = new \isys_cmdb_dao($g_comp_database_system);

    $idoitRootPath = str_replace('\\', '/', dirname(dirname(dirname(dirname(__DIR__))))) . '/';
    $filesystem = new Filesystem();

    $tenantDatabaseName = $daoTenant->convert_sql_text($g_comp_database->get_db_name());
    $tenantId = (int)$daoSystem
        ->retrieve("SELECT isys_mandator__id AS id FROM isys_mandator WHERE isys_mandator__db_name = {$tenantDatabaseName} LIMIT 1;")
        ->get_row_value('id');

    $objectTableConfiguration = [
        'cmdb.base-object-table.config.%' => 'system core configuration', // Provided by setup dump.
        'cmdb.default-object-table.config.%' => 'default configuration (provided by administrator)', // "Default" configuration, provided by admin.
    ];

    $g_migration_log[] = '<span class="bold">1. Migrate object table configurations.</span>';

    foreach ($objectTableConfiguration as $settingKey => $typeDescription) {
        $query = "SELECT isys_settings__key AS 'key', isys_settings__value AS 'value'
            FROM isys_settings
            WHERE isys_settings__key LIKE '{$settingKey}'
            AND isys_settings__isys_mandator__id = {$tenantId};";

        $result = $daoSystem->retrieve($query);

        $g_migration_log[] = '<span>Updating ' . count($result) . ' table configurations of type ' . $typeDescription . '.</span>';

        while ($row = $result->get_row()) {
            $key = $daoSystem->convert_sql_text($row['key']);
            $configuration = @unserialize(str_replace("�", "\0", $row['value']), ['allowed_classes' => [Config::class, Property::class]]);

            if (!$configuration || !($configuration instanceof Config)) {
                $g_migration_log[] = '<span class="indent">Could not read faulty configuration for <code style="margin:0">' . $row['key'] . '</code>, will remove.</span>';
                $updateQuery = "DELETE FROM isys_settings
                    WHERE isys_settings__key = {$key}
                    AND isys_settings__isys_mandator__id = {$tenantId}
                    LIMIT 1;";
            } else {
                $migratedConfiguration = $daoSystem->convert_sql_text($configuration->toJson());

                $updateQuery = "UPDATE isys_settings
                    SET isys_settings__value = {$migratedConfiguration}
                    WHERE isys_settings__key = {$key}
                    AND isys_settings__isys_mandator__id = {$tenantId}
                    LIMIT 1;";
            }

            $daoSystem->update($updateQuery);
            $daoSystem->apply_update();
        }
    }

    $categoryTableConfiguration = [
        'cmdb.multilist-table.default-config.%' => 'default configuration (provided by administrator)', // "Default" configuration, provided by admin.
        'cmdb.multilist-table.config.%' => 'user configuration' // Provided by user.
    ];

    $g_migration_log[] = '<span class="bold">2. Migrate category table configurations.</span>';

    foreach ($categoryTableConfiguration as $settingKey => $typeDescription) {
        $query = "SELECT isys_settings__key AS 'key', isys_settings__value AS 'value'
            FROM isys_settings
            WHERE isys_settings__key LIKE '{$settingKey}'
            AND isys_settings__isys_mandator__id = {$tenantId};";

        $result = $daoSystem->retrieve($query);

        $g_migration_log[] = '<span>Updating ' . count($result) . ' table configurations of type ' . $typeDescription . '.</span>';

        while ($row = $result->get_row()) {
            $key = $daoSystem->convert_sql_text($row['key']);
            $outerConfig = @unserialize(str_replace("�", "\0", $row['value']));
            $configuration = @unserialize($outerConfig['isys_obj_type_list__table_config'], ['allowed_classes' => [Config::class, Property::class]]);

            if (!$configuration || !($configuration instanceof Config)) {
                $g_migration_log[] = '<span class="indent">Could not read faulty configuration for <code style="margin:0">' . $row['key'] . '</code>, will remove.</span>';
                $updateQuery = "DELETE FROM isys_settings
                    WHERE isys_settings__key = {$key}
                    AND isys_settings__isys_mandator__id = {$tenantId}
                    LIMIT 1;";
            } else {
                $categoryIdentifier = substr($row['key'], strrpos($row['key'], '.') + 1);
                $outerConfig['isys_obj_type_list__table_config'] = $configuration->toJson($categoryIdentifier);

                $migratedConfiguration = $daoSystem->convert_sql_text(json_encode($outerConfig));

                $updateQuery = "UPDATE isys_settings
                    SET isys_settings__value = {$migratedConfiguration}
                    WHERE isys_settings__key = {$key}
                    AND isys_settings__isys_mandator__id = {$tenantId}
                    LIMIT 1;";
            }

            $daoSystem->update($updateQuery);
            $daoSystem->apply_update();
        }
    }

    $g_migration_log[] = '<span class="bold">3. Migrate user object table configurations.</span>';

    $query = "SELECT
        isys_obj_type_list__id AS id,
        isys_obj_type_list__table_config AS config,
        isys_obj_type_list__isys_obj__id AS userObjectId,
        isys_obj_type_list__isys_obj_type__id AS objectTypeId
        FROM isys_obj_type_list
        INNER JOIN isys_obj_type ON isys_obj_type__id = isys_obj_type_list__isys_obj_type__id;";

    $result = $daoTenant->retrieve($query);

    while ($row = $result->get_row()) {
        $g_migration_log[] = '<span>Migrate object type #' . $row['objectTypeId'] . ' table configuration for User #' . $row['userObjectId'] . '.</span>';

        try {
            $configuration = @unserialize(str_replace("�", "\0", $row['config']), ['allowed_classes' => [Config::class, Property::class]]);

            if (!$configuration instanceof Config) {
                throw new Exception('The configuration could not be unserialized properly.');
            }

            $id = $daoTenant->convert_sql_id($row['id']);
            $config = $daoTenant->convert_sql_text($configuration->toJson());

            $updateQuery = "UPDATE isys_obj_type_list
                SET isys_obj_type_list__table_config = {$config}
                WHERE isys_obj_type_list__id = {$id};";

            $daoTenant->update($updateQuery);
            $daoTenant->apply_update();
        } catch (Throwable $e) {
            $g_migration_log[] = '<span class="text-red">The table configuration could not be migrated. The user will need to re-save their configuration: ' . $e->getMessage() . '</span>';
        }
    }

    // Clearing the cache (again) is necessary, because at this time the current cache state contains the old settings.
    // They need to be rewritten with the updated ones.
    $g_migration_log[] = '<span class="bold">Force cache clear...</span>';

    try {
        $filesToClear = glob("$idoitRootPath/temp/cache_*", GLOB_ONLYDIR);
        $filesToClear[] = "$idoitRootPath/temp/settings.cache";
        $filesystem->remove($filesToClear);
        $g_migration_log[] = '<span>Done!</span>';
    } catch (Throwable $e) {
        $g_migration_log[] = '<span class="text-red">Error while clearing cache: ' . $e->getMessage() . '</span>';
    }

    $g_migration_log[] = '<span class="bold">Migration finished!</span>';

    $this->migration_done($migrationIdentifier);
}
