<?PHP
/**
 * Contains a class for keeping the Manticore actors fulltext index in sync.
 *
 * @author Joshua Ramon Enslin <joshua@museum-digital.de>
 */
declare(strict_types = 1);

/**
 * Class for keeping the actors fulltext index in sync.
 */
final class NodaPersinstFulltextSyncManticore {

    const FULL_SYNC_COMMIT_AFTER = 30000;

    /**
     * Returns all names and descriptions in the different languages of a actor.
     *
     * @param MDMysqli $mysqli_noda  DB connection.
     * @param string   $databasename Name of the DB connection.
     * @param integer  $id           ID of the entry to load.
     *
     * @return array<array{language: string, name: string, description: string, timestamp: string}>
     */
    public static function getAllNamesById(MDMysqli $mysqli_noda, string $databasename, int $id):array {

        $output = [];

        $result = $mysqli_noda->query_by_stmt("SELECT `persinst_anzeigename`, `persinst_kurzinfo`, `persinst_erfasst_am`
            FROM `$databasename`.`persinst`
            WHERE `persinst_id` = ?", "i", $id);

        if (!($data = $result->fetch_row())) {
            $result->close();
            return [];
        }

        $result->close();

        $output[] = [
            'language' => '',
            'name' => $data[0],
            'description' => $data[1],
            'timestamp' => $data[2],
        ];

        $result = $mysqli_noda->query_by_stmt("SELECT `trans_language`, REPLACE(CONCAT(`trans_name`, ' (', `persinst`.`persinst_geburtsjahr`, '-', `persinst`.`persinst_sterbejahr`, ')'), ' (-)', '') AS `trans_name`, `trans_description`, `trans_last`
            FROM `" . $databasename . "`.`persinst_translation`, `" . $databasename . "`.`persinst`
            WHERE `persinst_translation`.`persinst_id` = `persinst`.`persinst_id`
                AND `persinst`.`persinst_id` = ?", "i", $id);

        while ($cur = $result->fetch_row()) {

            $output[] = [
                'language' => $cur[0],
                'name' => $cur[1],
                'description' => $cur[2],
                'timestamp' => $cur[3],
            ];

        }

        $result->close();

        return $output;

    }

    /**
     * Removes all names of an entry from the Manticore index.
     *
     * @param MDMysqli $mysqli_manticore Connection to Manticore DB.
     * @param string   $databasename     Name of the main noda database.
     * @param integer  $id               ID of the entry to load.
     *
     * @return void
     */
    public static function removeById(MDMysqli $mysqli_manticore, string $databasename, int $id):void {

        $mysqli_manticore->do_update_query_large("DELETE FROM `" . $databasename . "_persinst`
            WHERE `entry_id` = " . $id);

    }

    /**
     * Inserts the names of an entry.
     *
     * @param MDMysqli $mysqli_noda      DB connection.
     * @param MDMysqli $mysqli_manticore Connection to Manticore DB.
     * @param string   $databasename     Name of the DB connection.
     * @param integer  $id               ID of the entry to load.
     *
     * @return void
     */
    public static function insertById(MDMysqli $mysqli_noda, MDMysqli $mysqli_manticore, string $databasename, int $id):void {

        $names = self::getAllNamesById($mysqli_noda, $databasename, $id);

        $mysqli_manticore->autocommit(false);

        foreach ($names as $cur) {

            $mysqli_manticore->query("INSERT INTO `" . $databasename . "_persinst`
                (`entry_id`, `language`, `name`, `description`, `timestamp`)
                VALUES
                (" . $id . ",
                    '" . $mysqli_manticore->escape_string($cur['language']) . "',
                    '" . $mysqli_manticore->escape_string($cur['name']) . "',
                    '" . $mysqli_manticore->escape_string($cur['description']) . "',
                    '" . strtotime($mysqli_manticore->escape_string($cur['timestamp'])) . "')");

            if ($mysqli_manticore->error) {
                throw new Exception($mysqli_manticore->error);
            }

        }

        $mysqli_manticore->commit();
        $mysqli_manticore->autocommit(true);

    }

    /**
     * Updates the names of an entry.
     *
     * @param MDMysqli $mysqli_noda      DB connection.
     * @param MDMysqli $mysqli_manticore Connection to Manticore DB.
     * @param string   $databasename     Name of the DB connection.
     * @param integer  $id               ID of the entry to load.
     *
     * @return void
     */
    public static function updateById(MDMysqli $mysqli_noda, MDMysqli $mysqli_manticore, string $databasename, int $id):void {

        self::removeById($mysqli_manticore, $databasename, $id);
        self::insertById($mysqli_noda, $mysqli_manticore, $databasename, $id);

    }

    /**
     * Runs a full sync.
     *
     * @param MDMysqli $mysqli_noda      Connection to MySQL DB.
     * @param MDMysqli $mysqli_manticore Connection to Manticore DB.
     * @param string   $databasename     Name of the main noda database.
     *
     * @return void
     */
    public static function runFullSync(MDMysqli $mysqli_noda, MDMysqli $mysqli_manticore, string $databasename):void {

        $mysqli_manticore->do_update_query_large("TRUNCATE RTINDEX `" . $databasename . "_persinst`");

        // Sync actors

        $i = 0;

        $result = $mysqli_noda->do_read_query("SELECT `persinst_id`, `persinst_anzeigename`, `persinst_kurzinfo`,
                `persinst_erfasst_am`
            FROM `" . $databasename . "`.`persinst`");

        $mysqli_manticore->autocommit(false);

        while ($cur = $result->fetch_assoc()) {

            $mysqli_manticore->query("INSERT INTO `" . $databasename . "_persinst`
                (`entry_id`, `language`, `name`, `description`, `timestamp`)
                VALUES
                (" . $cur['persinst_id'] . ",
                    '',
                    '" . $mysqli_manticore->escape_string($cur['persinst_anzeigename']) . "',
                    '" . $mysqli_manticore->escape_string($cur['persinst_kurzinfo']) . "',
                    '" . strtotime($mysqli_manticore->escape_string($cur['persinst_erfasst_am'])) . "')");

            if ($mysqli_manticore->error) {
                throw new Exception($mysqli_manticore->error);
            }

            MDConsole::write("Wrote {$cur['persinst_id']}");
            ++$i;
            if ($i === self::FULL_SYNC_COMMIT_AFTER) {
                $mysqli_manticore->commit();
                $i = 0;
            }

        }

        $result->close();

        $mysqli_manticore->commit();

        // Sync translations

        $result = $mysqli_noda->do_read_query("SELECT `persinst`.`persinst_id`, `trans_language`,
            REPLACE(CONCAT(`trans_name`, ' (', `persinst`.`persinst_geburtsjahr`, '-', `persinst`.`persinst_sterbejahr`, ')'), ' (-)', '') AS `trans_name`, `trans_description`, `trans_last`
                FROM `" . $databasename . "`.`persinst_translation`, `" . $databasename . "`.`persinst`
                WHERE `persinst_translation`.`persinst_id` = `persinst`.`persinst_id`");

        $i = 0;

        while ($cur = $result->fetch_assoc()) {

            $mysqli_manticore->query("INSERT INTO `" . $databasename . "_persinst`
                (`entry_id`, `language`, `name`, `description`, `timestamp`)
                VALUES
                (" . $cur['persinst_id'] . ",
                    '" . $mysqli_manticore->escape_string($cur['trans_language']) . "',
                    '" . $mysqli_manticore->escape_string($cur['trans_name']) . "',
                    '" . $mysqli_manticore->escape_string($cur['trans_description']) . "',
                    '" . strtotime($mysqli_manticore->escape_string($cur['trans_last'])) . "')");

            if ($mysqli_manticore->error) {
                throw new Exception($mysqli_manticore->error);
            }

            MDConsole::write("Wrote {$cur['persinst_id']}");
            ++$i;
            if ($i === self::FULL_SYNC_COMMIT_AFTER) {
                $mysqli_manticore->commit();
                $i = 0;
            }

        }

        $mysqli_manticore->commit();
        $mysqli_manticore->autocommit(true);

    }
}
