<?php

/**
 * i-doit - Updates
 *
 * Migrating reports to each tenant
 *
 * @package     i-doit
 * @subpackage  Update
 * @copyright   synetics GmbH
 * @license     http://www.i-doit.com/license
 */


/**
 * @var $g_comp_database isys_component_database
 */
global $g_comp_database, $g_comp_database_system;

// Set migrationId
$g_migration_identifier = 'report_visibility_migration';

if (!function_exists('generateReportConstant')) {
    /**
     * This function has been mostly copied from `isys_report_dao->generateReportConstant()` but uses a local array.
     *
     * @param string        $title
     * @param isys_cmdb_dao $dao
     * @param array         $usedConstants
     *
     * @return string
     * @throws isys_exception_database
     */
    function generateReportConstant(string $title, isys_cmdb_dao $dao, array $usedConstants): string
    {
        if (empty($title)) {
            // If the title is empty, we use a random hash.
            $title = md5(microtime());
        }

        // We'd like a constant that is shorter than 32 characters (29 + 'C__'), so we shorten it (this is optional, since the DB field has a length of 255).
        if (mb_strlen($title) > 29) {
            $title = substr($title, 0, 29);
        }

        /*
         * Here we generate a (unique) constant for the reports by a given title.
         *
         * 1) We remove all characters that are not "constant" compatible (with help of `isys_helper_upload::prepare_filename`).
         * 2) We then replace all hyphens `-` with underscroes `_`.
         * 3) Now we replace all remaining "non word characters" with nothing.
         * 4) And finally append `C__` and transform the string to upper case.
         */
        $newConstant = 'C__' . strtoupper(preg_replace('/\W+/', '', str_replace('-', '_', isys_helper_upload::prepare_filename($title))));

        // @see  ID-7235  We use the array instead of querying the database over and over.
        if (isset($usedConstants[$newConstant])) {
            $counter = 1;

            while (isset($usedConstants[$newConstant . $counter])) {
                $counter ++;
            }

            $newConstant .= $counter;
        }

        return $newConstant;
    }
}

// Check whether migration was executed before
if ($this->is_migration_done($g_migration_identifier)) {
    $g_migration_log[] = '<span class="bold">Reports have already been migrated.</span>';
} else {
    $g_migration_log[] = '<span class="bold">Starting migration of all reports to their assigned tenant.</span>';

    $dao = new isys_cmdb_dao($g_comp_database);
    $systemDao = new isys_cmdb_dao($g_comp_database_system);

    $adminUserId = $dao
        ->retrieve('SELECT isys_obj__id FROM isys_obj WHERE isys_obj__const = ' . $dao->convert_sql_text('C__OBJ__PERSON_ADMIN'))
        ->get_row_value('isys_obj__id');

    $result = $dao->retrieve('SELECT isys_obj_type__id FROM isys_obj_type WHERE isys_obj_type__isysgui_cats__id = (
        SELECT isysgui_cats__id FROM isysgui_cats WHERE isysgui_cats__const = \'C__CATS__PERSON\')');

    $objectTypeIds = [];
    while ($row = $result->get_row()) {
        $objectTypeIds[] = $row['isys_obj_type__id'];
    }

    $mandatorId = $systemDao
        ->retrieve('SELECT isys_mandator__id as id FROM isys_mandator WHERE isys_mandator__db_name = ' . $dao->convert_sql_text($g_comp_database->get_db_name()))
        ->get_row_value('id');

    $g_comp_database->query('SET FOREIGN_KEY_CHECKS = 0;');

    $reportCategoryGlobalId = $systemDao
        ->retrieve('SELECT isys_report_category__id as id FROM isys_report_category WHERE isys_report_category__title = \'Global\'')
        ->get_row_value('id');

    // @see  ID-7235  We read all constants (if they exist) and work with a local array instead of reading constants again and again.
    $usedConstants = [];

    $constantResult = $systemDao->retrieve("SELECT isys_report__const AS const FROM isys_report WHERE isys_report__const <> '';");

    while ($constantRow = $constantResult->get_row()) {
        $usedConstants[] = trim($constantRow['const']);
    }

    // Clean the "used constants" array.
    $usedConstants = array_flip(array_filter(array_unique($usedConstants)));

    // Migrate reports.
    $query = 'SELECT * FROM isys_report WHERE isys_report__mandator = ' . $dao->convert_sql_id($mandatorId);

    if ($reportCategoryGlobalId) {
        $query .= ' OR isys_report__isys_report_category__id = ' . $dao->convert_sql_id($reportCategoryGlobalId);
    }

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

    $reportCategoriesToMigrate = [];
    $g_comp_database->begin();

    try {
        if ($result->count()) {
            while ($row = $result->get_row()) {
                if ($row['isys_report__isys_report_category__id'] > 0 && !in_array($row['isys_report__isys_report_category__id'], $reportCategoriesToMigrate)) {
                    $reportCategoriesToMigrate[] = $row['isys_report__isys_report_category__id'];
                }

                $row['isys_report__mandator'] = $mandatorId;

                if ($row['isys_report__user']) {
                    $userData = $dao->get_object($row['isys_report__user'])->get_row();

                    if (isset($userData['isys_obj_type__id']) && !in_array($userData['isys_obj_type__id'], $objectTypeIds)) {
                        $row['isys_report__user'] = $adminUserId;
                    }
                } else {
                    $row['isys_report__user'] = $adminUserId;
                }

                if (empty($row['isys_report__const'])) {
                    $row['isys_report__const'] = generateReportConstant($row['isys_report__title'], $dao, $usedConstants, $g_migration_log);

                    // @see  ID-7235  Add the new constant to the array.
                    $usedConstants[$row['isys_report__const']] = true;
                }

                $g_migration_log[] = '<span class="indent">Migrating "' . $row['isys_report__title'] . '"</span>';

                $insertQuery = 'INSERT INTO isys_report VALUES (' . implode(',', array_map(function ($item) use ($dao) {
                    if ((is_numeric($item) && strlen((string)(int)$item) === strlen($item))) {
                        return $item;
                    }

                    if ($item === null) {
                        return 'NULL';
                    }

                    return $dao->convert_sql_text($item);
                }, $row)) . ')';

                $g_comp_database->query($insertQuery);
            }
        }

        $reportCategoriesToMigrate = array_filter($reportCategoriesToMigrate, function ($item) {
            return (is_numeric($item) && $item > 0);
        });

        if (count($reportCategoriesToMigrate) > 0) {
            $result = $systemDao->retrieve('SELECT * FROM isys_report_category WHERE isys_report_category__id IN (' . implode(',', $reportCategoriesToMigrate) . ')');

            if ($result->count()) {
                while ($row = $result->get_row()) {
                    $insertQuery = 'INSERT INTO isys_report_category VALUES (' . implode(',', array_map(function ($item) use ($dao) {
                        if ((is_numeric($item) && strlen((string)(int)$item) === strlen($item))) {
                            return $item;
                        }

                        if ($item === null) {
                            return 'NULL';
                        }

                        return $dao->convert_sql_text($item);
                    }, $row)) . ')';

                    $g_comp_database->query($insertQuery);
                }
            }
        }
        $g_comp_database->commit();
    } catch (Exception $e) {
        $g_migration_log[] = '<span class="bold red indent">An Error occurred with message: ' . $e->getMessage() . '</span>';
        $g_comp_database->rollback();
    }

    $g_comp_database->query('SET FOREIGN_KEY_CHECKS = 1;');

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

    // Mark migration as done
    $this->migration_done($g_migration_identifier);
}
