<?PHP
/**
 * Manages vocabulary groups.
 *
 * @file
 * @author Joshua Ramon Enslin <joshua@museum-digital.de>
 */
declare(strict_types = 1);

/**
 * Manages vocabulary groups.
 */
final class NodaGroup {

    private MDMysqli $_mysqli_noda;

    /**
     * Lists all active groups.
     *
     * @param integer $limit  Limit.
     * @param integer $offset Offset.
     *
     * @return array<array{id: int, name: string}>
     */
    public function list(int $limit = 50, int $offset = 0):array {

        $output = [];

        $result = $this->_mysqli_noda->query_by_stmt("SELECT `group_id`, `group_name`
            FROM `group`
            ORDER BY `group_id` DESC
            LIMIT ?
            OFFSET ?", "ii", $limit, $offset);

        while ($cur = $result->fetch_row()) {
            $output[] = [
                'id' => (int)$cur[0],
                'name' => $cur[1],
            ];
        }
        $result->close();

        return $output;

    }

    /**
     * Returns basic description of a group.
     *
     * @param integer $group_id Group ID.
     *
     * @return array{name: string, comment: string}
     */
    public function getDescription(int $group_id):array {

        $result = $this->_mysqli_noda->query_by_stmt("SELECT `group_name`, `comment`
            FROM `group`
            WHERE `group_id` = ?", "i", $group_id);

        if (!($cur = $result->fetch_row())) {
            $result->close();
            throw new MDmainEntityNotExistentException("This group does not seem to exist");
        }
        $result->close();

        return [
            'name' => $cur[0],
            'comment' => $cur[1],
        ];

    }

    /**
     * Adds a group.
     *
     * @param string $name    Name of the group.
     * @param string $comment Comment / note on the group.
     *
     * @return integer
     */
    public function insert(string $name, string $comment = ''):int {

        if (empty($name)) {
            throw new MDpageParameterMissingException("Name cannot be empty when adding groups.");
        }

        $insertStmt = $this->_mysqli_noda->do_prepare("INSERT INTO `group`
            (`group_name`, `comment`)
            VALUES
            (?, ?)");

        $insertStmt->bind_param("ss", $name, $comment);
        $insertStmt->execute();
        $output = $insertStmt->get_insert_id();
        $insertStmt->close();

        return $output;

    }

    /**
     * Updates a group.
     *
     * @param integer $group_id ID of the group to update.
     * @param string  $name     Name of the group.
     * @param string  $comment  Optional: Comment for the group.
     *
     * @return void
     */
    public function update(int $group_id, string $name, string $comment = ''):void {

        if (empty($name)) {
            throw new MDpageParameterMissingException("Name cannot be empty when adding groups.");
        }

        $insertStmt = $this->_mysqli_noda->do_prepare("UPDATE `group`
            SET `group_name` = ?,
                `comment` = ?
            WHERE `group_id` = ?");

        $insertStmt->bind_param("ssi", $name, $comment, $group_id);
        $insertStmt->execute();
        $insertStmt->close();

    }

    /**
     * Deletes a group.
     *
     * @param integer $group_id ID of the group to delete.
     *
     * @return void
     */
    public function delete(int $group_id):void {

        $this->_mysqli_noda->update_query_by_stmt("DELETE FROM `v_group_persinst`
            WHERE `group_id` = ?", "i", $group_id);
        $this->_mysqli_noda->update_query_by_stmt("DELETE FROM `v_group_orte`
            WHERE `group_id` = ?", "i", $group_id);
        $this->_mysqli_noda->update_query_by_stmt("DELETE FROM `v_group_zeiten`
            WHERE `group_id` = ?", "i", $group_id);
        $this->_mysqli_noda->update_query_by_stmt("DELETE FROM `v_group_tag`
            WHERE `group_id` = ?", "i", $group_id);

        $this->_mysqli_noda->update_query_by_stmt("DELETE FROM `group`
            WHERE `group_id` = ?", "i", $group_id);

    }

    /**
     * Adds actors to a nodac group.
     *
     * @param integer        $group_id  Group ID.
     * @param array<integer> $input_ids List of entries to link to the group.
     *
     * @return void
     */
    public function linkActors(int $group_id, array $input_ids):void {

        if (empty($input_ids = MD_STD_IN::sanitize_id_array($input_ids))) return;

        // Check which entries actually exist
        $idsToLink = [];
        $result = $this->_mysqli_noda->do_read_query("SELECT `persinst_id`
            FROM `persinst`
            WHERE `persinst_id` IN (" . $this->_mysqli_noda->escape_in($input_ids) . ")");

        while ($cur = $result->fetch_row()) {
            $idsToLink[] = (int)$cur[0];
        }
        $result->close();

        $this->_mysqli_noda->autocommit(false);

        $linkStmt = $this->_mysqli_noda->do_prepare("INSERT INTO `v_group_persinst`
            (`group_id`, `persinst_id`)
            VALUES (?, ?)");

        foreach ($idsToLink as $id) {
            $linkStmt->bind_param("ii", $group_id, $id);
            $linkStmt->execute();
        }
        $linkStmt->close();

        $this->_mysqli_noda->commit();
        $this->_mysqli_noda->autocommit(true);

    }

    /**
     * Adds places to a nodac group.
     *
     * @param integer        $group_id  Group ID.
     * @param array<integer> $input_ids List of entries to link to the group.
     *
     * @return void
     */
    public function linkPlaces(int $group_id, array $input_ids):void {

        if (empty($input_ids = MD_STD_IN::sanitize_id_array($input_ids))) return;

        // Check which entries actually exist
        $idsToLink = [];
        $result = $this->_mysqli_noda->do_read_query("SELECT `ort_id`
            FROM `orte`
            WHERE `ort_id` IN (" . $this->_mysqli_noda->escape_in($input_ids) . ")");

        while ($cur = $result->fetch_row()) {
            $idsToLink[] = (int)$cur[0];
        }
        $result->close();

        $this->_mysqli_noda->autocommit(false);

        $linkStmt = $this->_mysqli_noda->do_prepare("INSERT INTO `v_group_orte`
            (`group_id`, `ort_id`)
            VALUES (?, ?)");

        foreach ($idsToLink as $id) {
            $linkStmt->bind_param("ii", $group_id, $id);
            $linkStmt->execute();
        }
        $linkStmt->close();

        $this->_mysqli_noda->commit();
        $this->_mysqli_noda->autocommit(true);

    }

    /**
     * Adds times to a nodac group.
     *
     * @param integer        $group_id  Group ID.
     * @param array<integer> $input_ids List of entries to link to the group.
     *
     * @return void
     */
    public function linkTimes(int $group_id, array $input_ids):void {

        if (empty($input_ids = MD_STD_IN::sanitize_id_array($input_ids))) return;

        // Check which entries actually exist
        $idsToLink = [];
        $result = $this->_mysqli_noda->do_read_query("SELECT `zeit_id`
            FROM `zeiten`
            WHERE `zeit_id` IN (" . $this->_mysqli_noda->escape_in($input_ids) . ")");

        while ($cur = $result->fetch_row()) {
            $idsToLink[] = (int)$cur[0];
        }
        $result->close();

        $this->_mysqli_noda->autocommit(false);

        $linkStmt = $this->_mysqli_noda->do_prepare("INSERT INTO `v_group_zeiten`
            (`group_id`, `zeit_id`)
            VALUES (?, ?)");

        foreach ($idsToLink as $id) {
            $linkStmt->bind_param("ii", $group_id, $id);
            $linkStmt->execute();
        }
        $linkStmt->close();

        $this->_mysqli_noda->commit();
        $this->_mysqli_noda->autocommit(true);

    }

    /**
     * Adds tags to a nodac group.
     *
     * @param integer        $group_id  Group ID.
     * @param array<integer> $input_ids List of entries to link to the group.
     *
     * @return void
     */
    public function linkTags(int $group_id, array $input_ids):void {

        if (empty($input_ids = MD_STD_IN::sanitize_id_array($input_ids))) return;

        // Check which entries actually exist
        $idsToLink = [];
        $result = $this->_mysqli_noda->do_read_query("SELECT `tag_id`
            FROM `tag`
            WHERE `tag_id` IN (" . $this->_mysqli_noda->escape_in($input_ids) . ")");

        while ($cur = $result->fetch_row()) {
            $idsToLink[] = (int)$cur[0];
        }
        $result->close();

        $this->_mysqli_noda->autocommit(false);

        $linkStmt = $this->_mysqli_noda->do_prepare("INSERT INTO `v_group_tag`
            (`group_id`, `tag_id`)
            VALUES (?, ?)");

        foreach ($idsToLink as $id) {
            $linkStmt->bind_param("ii", $group_id, $id);
            $linkStmt->execute();
        }
        $linkStmt->close();

        $this->_mysqli_noda->commit();
        $this->_mysqli_noda->autocommit(true);

    }

    /**
     * Constructor.
     *
     * @param MDMysqli $mysqli_noda DB connection.
     *
     * @return void
     */
    public function __construct(MDMysqli $mysqli_noda) {

        $this->_mysqli_noda = $mysqli_noda;

    }
}
